Skip to content

Commit fea6845

Browse files
sheetalkamattypescript-bot
authored andcommitted
Cherry-pick PR microsoft#35111 into release-3.7
Component commits: 6945a72 Support dynamic file names with project root path Fixes microsoft#35094 cc30b36 Remove unexpected change
1 parent adaacd1 commit fea6845

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

src/server/editorServices.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,7 @@ namespace ts.server {
11411141

11421142
const project = this.getOrCreateInferredProjectForProjectRootPathIfEnabled(info, projectRootPath) ||
11431143
this.getOrCreateSingleInferredProjectIfEnabled() ||
1144-
this.getOrCreateSingleInferredWithoutProjectRoot(info.isDynamic ? this.currentDirectory : getDirectoryPath(info.path));
1144+
this.getOrCreateSingleInferredWithoutProjectRoot(info.isDynamic ? projectRootPath || this.currentDirectory : getDirectoryPath(info.path));
11451145

11461146
project.addRoot(info);
11471147
if (info.containingProjects[0] !== project) {
@@ -1503,6 +1503,8 @@ namespace ts.server {
15031503

15041504
Debug.assert(!isOpenScriptInfo(info) || this.openFiles.has(info.path));
15051505
const projectRootPath = this.openFiles.get(info.path);
1506+
const scriptInfo = Debug.assertDefined(this.getScriptInfo(info.path));
1507+
if (scriptInfo.isDynamic) return undefined;
15061508

15071509
let searchPath = asNormalizedPath(getDirectoryPath(info.fileName));
15081510
const isSearchPathInProjectRoot = () => containsPath(projectRootPath!, searchPath, this.currentDirectory, !this.host.useCaseSensitiveFileNames);
@@ -1943,7 +1945,9 @@ namespace ts.server {
19431945
}
19441946

19451947
private getOrCreateInferredProjectForProjectRootPathIfEnabled(info: ScriptInfo, projectRootPath: NormalizedPath | undefined): InferredProject | undefined {
1946-
if (info.isDynamic || !this.useInferredProjectPerProjectRoot) {
1948+
if (!this.useInferredProjectPerProjectRoot ||
1949+
// Its a dynamic info opened without project root
1950+
(info.isDynamic && projectRootPath === undefined)) {
19471951
return undefined;
19481952
}
19491953

@@ -2228,7 +2232,7 @@ namespace ts.server {
22282232
const isDynamic = isDynamicFileName(fileName);
22292233
Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info or in context of host currentDirectory`);
22302234
Debug.assert(!isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nOpen script files with non rooted disk path opened with current directory context cannot have same canonical names`);
2231-
Debug.assert(!isDynamic || this.currentDirectory === currentDirectory, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nDynamic files must always have current directory context since containing external project name will always match the script info name.`);
2235+
Debug.assert(!isDynamic || this.currentDirectory === currentDirectory || this.useInferredProjectPerProjectRoot, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nDynamic files must always be opened with service's current directory or service should support inferred project per projectRootPath.`);
22322236
// If the file is not opened by client and the file doesnot exist on the disk, return
22332237
if (!openedByClient && !isDynamic && !(hostToQueryFileExistsOn || this.host).fileExists(fileName)) {
22342238
return;
@@ -2239,7 +2243,7 @@ namespace ts.server {
22392243
if (!openedByClient) {
22402244
this.watchClosedScriptInfo(info);
22412245
}
2242-
else if (!isRootedDiskPath(fileName) && !isDynamic) {
2246+
else if (!isRootedDiskPath(fileName) && (!isDynamic || this.currentDirectory !== currentDirectory)) {
22432247
// File that is opened by user but isn't rooted disk path
22442248
this.openFilesWithNonRootedDiskPath.set(this.toCanonicalFileName(fileName), info);
22452249
}

src/testRunner/unittests/tsserver/projects.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,62 @@ var x = 10;`
11311131
checkProjectActualFiles(project, [file.path, libFile.path]);
11321132
});
11331133

1134+
describe("dynamic file with projectRootPath", () => {
1135+
const file: File = {
1136+
path: "^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js",
1137+
content: "var x = 10;"
1138+
};
1139+
const configFile: File = {
1140+
path: `${projectRoot}/tsconfig.json`,
1141+
content: "{}"
1142+
};
1143+
const configProjectFile: File = {
1144+
path: `${projectRoot}/a.ts`,
1145+
content: "let y = 10;"
1146+
};
1147+
it("with useInferredProjectPerProjectRoot", () => {
1148+
const host = createServerHost([libFile, configFile, configProjectFile], { useCaseSensitiveFileNames: true });
1149+
const session = createSession(host, { useInferredProjectPerProjectRoot: true });
1150+
openFilesForSession([{ file: file.path, projectRootPath: projectRoot }], session);
1151+
1152+
const projectService = session.getProjectService();
1153+
checkNumberOfProjects(projectService, { inferredProjects: 1 });
1154+
checkProjectActualFiles(projectService.inferredProjects[0], [file.path, libFile.path]);
1155+
1156+
session.executeCommandSeq<protocol.OutliningSpansRequest>({
1157+
command: protocol.CommandTypes.GetOutliningSpans,
1158+
arguments: {
1159+
file: file.path
1160+
}
1161+
});
1162+
1163+
// Without project root
1164+
const file2Path = file.path.replace("#1", "#2");
1165+
projectService.openClientFile(file2Path, file.content);
1166+
checkNumberOfProjects(projectService, { inferredProjects: 2 });
1167+
checkProjectActualFiles(projectService.inferredProjects[0], [file.path, libFile.path]);
1168+
checkProjectActualFiles(projectService.inferredProjects[1], [file2Path, libFile.path]);
1169+
});
1170+
1171+
it("fails when useInferredProjectPerProjectRoot is false", () => {
1172+
const host = createServerHost([libFile, configFile, configProjectFile], { useCaseSensitiveFileNames: true });
1173+
const projectService = createProjectService(host);
1174+
try {
1175+
projectService.openClientFile(file.path, file.content, /*scriptKind*/ undefined, projectRoot);
1176+
}
1177+
catch (e) {
1178+
assert.strictEqual(
1179+
e.message.replace(/\r?\n/, "\n"),
1180+
`Debug Failure. False expression: \nVerbose Debug Information: {"fileName":"^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js","currentDirectory":"/user/username/projects/myproject","hostCurrentDirectory":"/","openKeys":[]}\nDynamic files must always be opened with service's current directory or service should support inferred project per projectRootPath.`
1181+
);
1182+
}
1183+
const file2Path = file.path.replace("#1", "#2");
1184+
projectService.openClientFile(file2Path, file.content);
1185+
projectService.checkNumberOfProjects({ inferredProjects: 1 });
1186+
checkProjectActualFiles(projectService.inferredProjects[0], [file2Path, libFile.path]);
1187+
});
1188+
});
1189+
11341190
it("files opened, closed affecting multiple projects", () => {
11351191
const file: File = {
11361192
path: "/a/b/projects/config/file.ts",

0 commit comments

Comments
 (0)