Skip to content

Commit af371e1

Browse files
committed
Fix rewatch lockfile detection on Windows by correcting project root lookup logic
Refactor findProjectRootOfFile to use separate functions for file vs directory lookups, eliminating confusing boolean parameter and fixing the case where exact directory matches were incorrectly excluded.
1 parent a1b41a7 commit af371e1

File tree

2 files changed

+89
-23
lines changed

2 files changed

+89
-23
lines changed

server/src/incrementalCompilation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ function triggerIncrementalCompilationOfFile(
277277
const foundRewatchLockfileInProjectRoot =
278278
computedWorkspaceRoot == null &&
279279
projectRootPath != null &&
280-
utils.findProjectRootOfFile(projectRootPath, true) != null;
280+
utils.findProjectRootOfDir(projectRootPath) != null;
281281

282282
if (foundRewatchLockfileInProjectRoot && debug()) {
283283
console.log(

server/src/utils.ts

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ export let createFileInTempDir = (extension = ""): NormalizedPath => {
8282
return path.join(os.tmpdir(), tempFileName) as NormalizedPath;
8383
};
8484

85-
let findProjectRootOfFileInDir = (
85+
function findProjectRootOfFileInDir(
8686
source: NormalizedPath,
87-
): NormalizedPath | null => {
87+
): NormalizedPath | null {
8888
const dir = normalizePath(path.dirname(source));
8989
if (dir == null) {
9090
return null;
@@ -102,18 +102,20 @@ let findProjectRootOfFileInDir = (
102102
return findProjectRootOfFileInDir(dir);
103103
}
104104
}
105-
};
105+
}
106106

107-
// TODO: races here?
108-
export let findProjectRootOfFile = (
107+
/**
108+
* Searches for a project root path in projectsFiles that contains the given file path.
109+
* Excludes exact matches - the source must be a file inside a project, not the project root itself.
110+
*/
111+
function findProjectRootContainingFile(
109112
source: NormalizedPath,
110-
allowDir?: boolean,
111-
): NormalizedPath | null => {
112-
// First look in project files (keys are already normalized)
113+
): NormalizedPath | null {
113114
let foundRootFromProjectFiles: NormalizedPath | null = null;
114115
for (const rootPath of projectsFiles.keys()) {
115116
// Both are normalized, so direct comparison works
116-
if (source.startsWith(rootPath) && (!allowDir || source !== rootPath)) {
117+
// For files, we exclude exact matches (source !== rootPath)
118+
if (source.startsWith(rootPath) && source !== rootPath) {
117119
// Prefer the longest path (most nested)
118120
if (
119121
foundRootFromProjectFiles == null ||
@@ -124,20 +126,77 @@ export let findProjectRootOfFile = (
124126
}
125127
}
126128

127-
if (foundRootFromProjectFiles != null) {
128-
return foundRootFromProjectFiles;
129-
} else {
130-
const isDir = path.extname(source) === "";
131-
const searchPath =
132-
isDir && !allowDir ? path.join(source, "dummy.res") : source;
133-
const normalizedSearchPath = normalizePath(searchPath);
134-
if (normalizedSearchPath == null) {
135-
return null;
129+
return foundRootFromProjectFiles;
130+
}
131+
132+
/**
133+
* Searches for a project root path in projectsFiles that matches the given directory path.
134+
* Allows exact matches - the source can be the project root directory itself.
135+
*/
136+
function findProjectRootMatchingDir(
137+
source: NormalizedPath,
138+
): NormalizedPath | null {
139+
console.log({
140+
source,
141+
searchType: "directory",
142+
projectsFilesKeys: Array.from(projectsFiles.keys()),
143+
});
144+
145+
let foundRootFromProjectFiles: NormalizedPath | null = null;
146+
for (const rootPath of projectsFiles.keys()) {
147+
// Both are normalized, so direct comparison works
148+
// For directories, we allow exact matches
149+
if (source.startsWith(rootPath)) {
150+
// Prefer the longest path (most nested)
151+
if (
152+
foundRootFromProjectFiles == null ||
153+
rootPath.length > foundRootFromProjectFiles.length
154+
) {
155+
foundRootFromProjectFiles = rootPath;
156+
}
136157
}
137-
const foundPath = findProjectRootOfFileInDir(normalizedSearchPath);
138-
return foundPath;
139158
}
140-
};
159+
160+
return foundRootFromProjectFiles;
161+
}
162+
163+
/**
164+
* Finds the project root for a given file path.
165+
* This is the main function used throughout the codebase for finding project roots.
166+
*/
167+
export function findProjectRootOfFile(
168+
source: NormalizedPath,
169+
): NormalizedPath | null {
170+
// First look in project files - exclude exact matches since we're looking for a file
171+
let foundRoot = findProjectRootContainingFile(source);
172+
173+
if (foundRoot != null) {
174+
return foundRoot;
175+
}
176+
177+
// Fallback: search the filesystem
178+
const foundPath = findProjectRootOfFileInDir(source);
179+
return foundPath;
180+
}
181+
182+
/**
183+
* Finds the project root for a given directory path.
184+
* This allows exact matches and is used for workspace/lockfile detection.
185+
*/
186+
export function findProjectRootOfDir(
187+
source: NormalizedPath,
188+
): NormalizedPath | null {
189+
// First look in project files - allow exact matches since we're looking for a directory
190+
let foundRoot = findProjectRootMatchingDir(source);
191+
192+
if (foundRoot != null) {
193+
return foundRoot;
194+
}
195+
196+
// Fallback: search the filesystem
197+
const foundPath = findProjectRootOfFileInDir(source);
198+
return foundPath;
199+
}
141200

142201
/**
143202
* Gets the project file for a given project root path.
@@ -493,14 +552,21 @@ export function computeWorkspaceRootPathFromLockfile(
493552
path.resolve(projectRootPath, rescriptLockPartialPath),
494553
];
495554

555+
console.log(projectRewatchLockfiles);
556+
496557
const foundRewatchLockfileInProjectRoot = projectRewatchLockfiles.some(
497558
(lockFile) => fs.existsSync(lockFile),
498559
);
499560

561+
console.log(
562+
"foundRewatchLockfileInProjectRoot",
563+
foundRewatchLockfileInProjectRoot,
564+
);
565+
500566
// if we find a rewatch.lock in the project root, it's a compilation of a local package
501567
// in the workspace.
502568
return !foundRewatchLockfileInProjectRoot
503-
? findProjectRootOfFile(projectRootPath, true)
569+
? findProjectRootOfDir(projectRootPath)
504570
: null;
505571
}
506572

0 commit comments

Comments
 (0)