@@ -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