Skip to content

Commit e8fd1cf

Browse files
authored
Support project root path for controlling config file searching depth (#15238)
* stops at projectRootPath when searching config file * Add tests * Update editorServices.ts Remove extra `true &&`
1 parent 5819402 commit e8fd1cf

File tree

4 files changed

+44
-11
lines changed

4 files changed

+44
-11
lines changed

src/harness/unittests/tsserverProjectSystem.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3493,6 +3493,30 @@ namespace ts.projectSystem {
34933493
});
34943494
});
34953495

3496+
describe("searching for config file", () => {
3497+
it("should stop at projectRootPath if given", () => {
3498+
const f1 = {
3499+
path: "/a/file1.ts",
3500+
content: ""
3501+
};
3502+
const configFile = {
3503+
path: "/tsconfig.json",
3504+
content: "{}"
3505+
};
3506+
const host = createServerHost([f1, configFile]);
3507+
const service = createProjectService(host);
3508+
service.openClientFile(f1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, "/a");
3509+
3510+
checkNumberOfConfiguredProjects(service, 0);
3511+
checkNumberOfInferredProjects(service, 1);
3512+
3513+
service.closeClientFile(f1.path);
3514+
service.openClientFile(f1.path);
3515+
checkNumberOfConfiguredProjects(service, 1);
3516+
checkNumberOfInferredProjects(service, 0);
3517+
});
3518+
});
3519+
34963520
describe("cancellationToken", () => {
34973521
it("is attached to request", () => {
34983522
const f1 = {

src/server/editorServices.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -787,12 +787,12 @@ namespace ts.server {
787787
* we first detect if there is already a configured project created for it: if so, we re-read
788788
* the tsconfig file content and update the project; otherwise we create a new one.
789789
*/
790-
private openOrUpdateConfiguredProjectForFile(fileName: NormalizedPath): OpenConfiguredProjectResult {
790+
private openOrUpdateConfiguredProjectForFile(fileName: NormalizedPath, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult {
791791
const searchPath = getDirectoryPath(fileName);
792792
this.logger.info(`Search path: ${searchPath}`);
793793

794794
// check if this file is already included in one of external projects
795-
const configFileName = this.findConfigFile(asNormalizedPath(searchPath));
795+
const configFileName = this.findConfigFile(asNormalizedPath(searchPath), projectRootPath);
796796
if (!configFileName) {
797797
this.logger.info("No config files found.");
798798
return {};
@@ -826,8 +826,8 @@ namespace ts.server {
826826
// current directory (the directory in which tsc was invoked).
827827
// The server must start searching from the directory containing
828828
// the newly opened file.
829-
private findConfigFile(searchPath: NormalizedPath): NormalizedPath {
830-
while (true) {
829+
private findConfigFile(searchPath: NormalizedPath, projectRootPath?: NormalizedPath): NormalizedPath {
830+
while (!projectRootPath || searchPath.indexOf(projectRootPath) >= 0) {
831831
const tsconfigFileName = asNormalizedPath(combinePaths(searchPath, "tsconfig.json"));
832832
if (this.host.fileExists(tsconfigFileName)) {
833833
return tsconfigFileName;
@@ -1326,17 +1326,17 @@ namespace ts.server {
13261326
* @param filename is absolute pathname
13271327
* @param fileContent is a known version of the file content that is more up to date than the one on disk
13281328
*/
1329-
openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind): OpenConfiguredProjectResult {
1330-
return this.openClientFileWithNormalizedPath(toNormalizedPath(fileName), fileContent, scriptKind);
1329+
openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind, projectRootPath?: string): OpenConfiguredProjectResult {
1330+
return this.openClientFileWithNormalizedPath(toNormalizedPath(fileName), fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath ? toNormalizedPath(projectRootPath) : undefined);
13311331
}
13321332

1333-
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean): OpenConfiguredProjectResult {
1333+
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult {
13341334
let configFileName: NormalizedPath;
13351335
let configFileErrors: Diagnostic[];
13361336

13371337
let project: ConfiguredProject | ExternalProject = this.findContainingExternalProject(fileName);
13381338
if (!project) {
1339-
({ configFileName, configFileErrors } = this.openOrUpdateConfiguredProjectForFile(fileName));
1339+
({ configFileName, configFileErrors } = this.openOrUpdateConfiguredProjectForFile(fileName, projectRootPath));
13401340
if (configFileName) {
13411341
project = this.findConfiguredProjectByProjectName(configFileName);
13421342
}

src/server/protocol.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,11 @@ namespace ts.server.protocol {
10411041
* "TS", "JS", "TSX", "JSX"
10421042
*/
10431043
scriptKindName?: ScriptKindName;
1044+
/**
1045+
* Used to limit the searching for project config file. If given the searching will stop at this
1046+
* root path; otherwise it will go all the way up to the dist root path.
1047+
*/
1048+
projectRootPath?: string;
10441049
}
10451050

10461051
export type ScriptKindName = "TS" | "JS" | "TSX" | "JSX";

src/server/session.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -979,8 +979,8 @@ namespace ts.server {
979979
* @param fileName is the name of the file to be opened
980980
* @param fileContent is a version of the file content that is known to be more up to date than the one on disk
981981
*/
982-
private openClientFile(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind) {
983-
const { configFileName, configFileErrors } = this.projectService.openClientFileWithNormalizedPath(fileName, fileContent, scriptKind);
982+
private openClientFile(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, projectRootPath?: NormalizedPath) {
983+
const { configFileName, configFileErrors } = this.projectService.openClientFileWithNormalizedPath(fileName, fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath);
984984
if (this.eventHandler) {
985985
this.eventHandler({
986986
eventName: "configFileDiag",
@@ -1659,7 +1659,11 @@ namespace ts.server {
16591659
return this.requiredResponse(this.getRenameInfo(request.arguments));
16601660
},
16611661
[CommandNames.Open]: (request: protocol.OpenRequest) => {
1662-
this.openClientFile(toNormalizedPath(request.arguments.file), request.arguments.fileContent, convertScriptKindName(request.arguments.scriptKindName));
1662+
this.openClientFile(
1663+
toNormalizedPath(request.arguments.file),
1664+
request.arguments.fileContent,
1665+
convertScriptKindName(request.arguments.scriptKindName),
1666+
request.arguments.projectRootPath ? toNormalizedPath(request.arguments.projectRootPath) : undefined);
16631667
return this.notRequired();
16641668
},
16651669
[CommandNames.Quickinfo]: (request: protocol.QuickInfoRequest) => {

0 commit comments

Comments
 (0)