Skip to content

Commit ad3e449

Browse files
sheetalkamattimsuchanek
authored andcommitted
Handle network style paths for watching (microsoft#32888)
* Refactoring * take windows style root as test server host parameter * Handle network style paths for watching Fixes microsoft#32796
1 parent dee0a69 commit ad3e449

File tree

4 files changed

+89
-37
lines changed

4 files changed

+89
-37
lines changed

src/compiler/resolutionCache.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,36 @@ namespace ts {
9090
return false;
9191
}
9292

93-
const nextDirectorySeparator = dirPath.indexOf(directorySeparator, rootLength);
93+
let nextDirectorySeparator = dirPath.indexOf(directorySeparator, rootLength);
9494
if (nextDirectorySeparator === -1) {
9595
// ignore "/user", "c:/users" or "c:/folderAtRoot"
9696
return false;
9797
}
9898

99-
if (dirPath.charCodeAt(0) !== CharacterCodes.slash &&
100-
dirPath.substr(rootLength, nextDirectorySeparator).search(/users/i) === -1) {
99+
let pathPartForUserCheck = dirPath.substring(rootLength, nextDirectorySeparator + 1);
100+
const isNonDirectorySeparatorRoot = rootLength > 1 || dirPath.charCodeAt(0) !== CharacterCodes.slash;
101+
if (isNonDirectorySeparatorRoot &&
102+
dirPath.search(/[a-zA-Z]:/) !== 0 && // Non dos style paths
103+
pathPartForUserCheck.search(/[a-zA-z]\$\//) === 0) { // Dos style nextPart
104+
nextDirectorySeparator = dirPath.indexOf(directorySeparator, nextDirectorySeparator + 1);
105+
if (nextDirectorySeparator === -1) {
106+
// ignore "//vda1cs4850/c$/folderAtRoot"
107+
return false;
108+
}
109+
110+
pathPartForUserCheck = dirPath.substring(rootLength + pathPartForUserCheck.length, nextDirectorySeparator + 1);
111+
}
112+
113+
if (isNonDirectorySeparatorRoot &&
114+
pathPartForUserCheck.search(/users\//i) !== 0) {
101115
// Paths like c:/folderAtRoot/subFolder are allowed
102116
return true;
103117
}
104118

105119
for (let searchIndex = nextDirectorySeparator + 1, searchLevels = 2; searchLevels > 0; searchLevels--) {
106120
searchIndex = dirPath.indexOf(directorySeparator, searchIndex) + 1;
107121
if (searchIndex === 0) {
108-
// Folder isnt at expected minimun levels
122+
// Folder isnt at expected minimum levels
109123
return false;
110124
}
111125
}

src/harness/virtualFileSystemWithWatch.ts

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -35,38 +35,16 @@ interface Array<T> { length: number; [n: number]: T; }`
3535
executingFilePath?: string;
3636
currentDirectory?: string;
3737
newLine?: string;
38-
useWindowsStylePaths?: boolean;
38+
windowsStyleRoot?: string;
3939
environmentVariables?: Map<string>;
4040
}
4141

4242
export function createWatchedSystem(fileOrFolderList: ReadonlyArray<FileOrFolderOrSymLink>, params?: TestServerHostCreationParameters): TestServerHost {
43-
if (!params) {
44-
params = {};
45-
}
46-
const host = new TestServerHost(/*withSafelist*/ false,
47-
params.useCaseSensitiveFileNames !== undefined ? params.useCaseSensitiveFileNames : false,
48-
params.executingFilePath || getExecutingFilePathFromLibFile(),
49-
params.currentDirectory || "/",
50-
fileOrFolderList,
51-
params.newLine,
52-
params.useWindowsStylePaths,
53-
params.environmentVariables);
54-
return host;
43+
return new TestServerHost(/*withSafelist*/ false, fileOrFolderList, params);
5544
}
5645

5746
export function createServerHost(fileOrFolderList: ReadonlyArray<FileOrFolderOrSymLink>, params?: TestServerHostCreationParameters): TestServerHost {
58-
if (!params) {
59-
params = {};
60-
}
61-
const host = new TestServerHost(/*withSafelist*/ true,
62-
params.useCaseSensitiveFileNames !== undefined ? params.useCaseSensitiveFileNames : false,
63-
params.executingFilePath || getExecutingFilePathFromLibFile(),
64-
params.currentDirectory || "/",
65-
fileOrFolderList,
66-
params.newLine,
67-
params.useWindowsStylePaths,
68-
params.environmentVariables);
69-
return host;
47+
return new TestServerHost(/*withSafelist*/ true, fileOrFolderList, params);
7048
}
7149

7250
export interface File {
@@ -326,6 +304,16 @@ interface Array<T> { length: number; [n: number]: T; }`
326304
}
327305

328306
const timeIncrements = 1000;
307+
export interface TestServerHostOptions {
308+
useCaseSensitiveFileNames: boolean;
309+
executingFilePath: string;
310+
currentDirectory: string;
311+
fileOrFolderorSymLinkList: ReadonlyArray<FileOrFolderOrSymLink>;
312+
newLine?: string;
313+
useWindowsStylePaths?: boolean;
314+
environmentVariables?: Map<string>;
315+
}
316+
329317
export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, ModuleResolutionHost {
330318
args: string[] = [];
331319

@@ -342,16 +330,31 @@ interface Array<T> { length: number; [n: number]: T; }`
342330
readonly watchedDirectories = createMultiMap<TestDirectoryWatcher>();
343331
readonly watchedDirectoriesRecursive = createMultiMap<TestDirectoryWatcher>();
344332
readonly watchedFiles = createMultiMap<TestFileWatcher>();
333+
public readonly useCaseSensitiveFileNames: boolean;
334+
public readonly newLine: string;
335+
public readonly windowsStyleRoot?: string;
336+
private readonly environmentVariables?: Map<string>;
345337
private readonly executingFilePath: string;
346338
private readonly currentDirectory: string;
347339
private readonly customWatchFile: HostWatchFile | undefined;
348340
private readonly customRecursiveWatchDirectory: HostWatchDirectory | undefined;
349341
public require: ((initialPath: string, moduleName: string) => server.RequireResult) | undefined;
350342

351-
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, executingFilePath: string, currentDirectory: string, fileOrFolderorSymLinkList: ReadonlyArray<FileOrFolderOrSymLink>, public readonly newLine = "\n", public readonly useWindowsStylePath?: boolean, private readonly environmentVariables?: Map<string>) {
352-
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
343+
constructor(
344+
public withSafeList: boolean,
345+
fileOrFolderorSymLinkList: ReadonlyArray<FileOrFolderOrSymLink>,
346+
{
347+
useCaseSensitiveFileNames, executingFilePath, currentDirectory,
348+
newLine, windowsStyleRoot, environmentVariables
349+
}: TestServerHostCreationParameters = {}) {
350+
this.useCaseSensitiveFileNames = !!useCaseSensitiveFileNames;
351+
this.newLine = newLine || "\n";
352+
this.windowsStyleRoot = windowsStyleRoot;
353+
this.environmentVariables = environmentVariables;
354+
currentDirectory = currentDirectory || "/";
355+
this.getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames);
353356
this.toPath = s => toPath(s, currentDirectory, this.getCanonicalFileName);
354-
this.executingFilePath = this.getHostSpecificPath(executingFilePath);
357+
this.executingFilePath = this.getHostSpecificPath(executingFilePath || getExecutingFilePathFromLibFile());
355358
this.currentDirectory = this.getHostSpecificPath(currentDirectory);
356359
this.reloadFS(fileOrFolderorSymLinkList);
357360
const tscWatchFile = this.environmentVariables && this.environmentVariables.get("TSC_WATCHFILE") as Tsc_WatchFile;
@@ -418,8 +421,8 @@ interface Array<T> { length: number; [n: number]: T; }`
418421
}
419422

420423
getHostSpecificPath(s: string) {
421-
if (this.useWindowsStylePath && s.startsWith(directorySeparator)) {
422-
return "c:/" + s.substring(1);
424+
if (this.windowsStyleRoot && s.startsWith(directorySeparator)) {
425+
return this.windowsStyleRoot + s.substring(1);
423426
}
424427
return s;
425428
}
@@ -433,7 +436,7 @@ interface Array<T> { length: number; [n: number]: T; }`
433436
const mapNewLeaves = createMap<true>();
434437
const isNewFs = this.fs.size === 0;
435438
fileOrFolderOrSymLinkList = fileOrFolderOrSymLinkList.concat(this.withSafeList ? safeList : []);
436-
const filesOrFoldersToLoad: ReadonlyArray<FileOrFolderOrSymLink> = !this.useWindowsStylePath ? fileOrFolderOrSymLinkList :
439+
const filesOrFoldersToLoad: ReadonlyArray<FileOrFolderOrSymLink> = !this.windowsStyleRoot ? fileOrFolderOrSymLinkList :
437440
fileOrFolderOrSymLinkList.map<FileOrFolderOrSymLink>(f => {
438441
const result = clone(f);
439442
result.path = this.getHostSpecificPath(f.path);

src/testRunner/unittests/tsserver/projects.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ namespace ts.projectSystem {
10611061
content: "let x = 1;"
10621062
};
10631063

1064-
const host = createServerHost([file1, configFile], { useWindowsStylePaths: true });
1064+
const host = createServerHost([file1, configFile], { windowsStyleRoot: "c:/" });
10651065
const projectService = createProjectService(host);
10661066

10671067
projectService.openClientFile(file1.path);

src/testRunner/unittests/tsserver/watchEnvironment.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ namespace ts.projectSystem {
9999
content: "let y = 10;"
100100
};
101101
const files = [configFile, file1, file2, libFile];
102-
const host = createServerHost(files, { useWindowsStylePaths: true });
102+
const host = createServerHost(files, { windowsStyleRoot: "c:/" });
103103
const projectService = createProjectService(host);
104104
projectService.openClientFile(file1.path);
105105
const project = projectService.configuredProjects.get(configFile.path)!;
@@ -211,4 +211,39 @@ namespace ts.projectSystem {
211211
}
212212
});
213213

214+
describe("unittests:: tsserver:: watchEnvironment:: tsserverProjectSystem watching files with network style paths", () => {
215+
function verifyFilePathStyle(path: string) {
216+
const windowsStyleRoot = path.substr(0, getRootLength(path));
217+
const host = createServerHost(
218+
[libFile, { path, content: "const x = 10" }],
219+
{ windowsStyleRoot }
220+
);
221+
const service = createProjectService(host);
222+
service.openClientFile(path);
223+
checkNumberOfProjects(service, { inferredProjects: 1 });
224+
const libPath = `${windowsStyleRoot}${libFile.path.substring(1)}`;
225+
checkProjectActualFiles(service.inferredProjects[0], [path, libPath]);
226+
checkWatchedFiles(host, [libPath, `${getDirectoryPath(path)}/tsconfig.json`, `${getDirectoryPath(path)}/jsconfig.json`]);
227+
}
228+
229+
it("for file of style c:/myprojects/project/x.js", () => {
230+
verifyFilePathStyle("c:/myprojects/project/x.js");
231+
});
232+
233+
it("for file of style //vda1cs4850/myprojects/project/x.js", () => {
234+
verifyFilePathStyle("//vda1cs4850/myprojects/project/x.js");
235+
});
236+
237+
it("for file of style //vda1cs4850/c$/myprojects/project/x.js", () => {
238+
verifyFilePathStyle("//vda1cs4850/c$/myprojects/project/x.js");
239+
});
240+
241+
it("for file of style c:/users/username/myprojects/project/x.js", () => {
242+
verifyFilePathStyle("c:/users/username/myprojects/project/x.js");
243+
});
244+
245+
it("for file of style //vda1cs4850/c$/users/username/myprojects/project/x.js", () => {
246+
verifyFilePathStyle("//vda1cs4850/c$/users/username/myprojects/project/x.js");
247+
});
248+
});
214249
}

0 commit comments

Comments
 (0)