@@ -158,6 +158,54 @@ async function findProjectRootForFile(filePath: string, workspaceRoot: string):
158158 return undefined ;
159159}
160160
161+ // Helper function to detect monorepo and find all projects with ReScript config
162+ async function detectMonorepoProjects ( workspaceRoot : string ) : Promise < vscode . Uri [ ] > {
163+ // Find all bsconfig.json or rescript.json files in the workspace
164+ const bsconfigFiles = await vscode . workspace . findFiles (
165+ new vscode . RelativePattern ( workspaceRoot , '**/bsconfig.json' ) ,
166+ '**/node_modules/**' , // exclude node_modules
167+ ) ;
168+
169+ const rescriptFiles = await vscode . workspace . findFiles (
170+ new vscode . RelativePattern ( workspaceRoot , '**/rescript.json' ) ,
171+ '**/node_modules/**' , // exclude node_modules
172+ ) ;
173+
174+ // Combine both types of config files
175+ const allConfigFiles = [ ...bsconfigFiles , ...rescriptFiles ] ;
176+
177+ // If there's more than one config file, it might be a monorepo
178+ if ( allConfigFiles . length > 1 ) {
179+ return allConfigFiles ;
180+ }
181+
182+ return [ ] ;
183+ }
184+
185+ // Function to prompt user to select a project from a monorepo
186+ async function selectMonorepoProject ( projects : vscode . Uri [ ] ) : Promise < string | undefined > {
187+ // Create QuickPick items from project paths
188+ const items = projects . map ( uri => {
189+ const relativePath = vscode . workspace . asRelativePath ( uri ) ;
190+ const projectDir = path . dirname ( uri . fsPath ) ;
191+ const projectName = path . basename ( projectDir ) ;
192+
193+ return {
194+ label : projectName ,
195+ description : relativePath ,
196+ projectRoot : projectDir
197+ } ;
198+ } ) ;
199+
200+ // Show QuickPick to user
201+ const selectedItem = await vscode . window . showQuickPick ( items , {
202+ placeHolder : 'Select a ReScript project to analyze' ,
203+ title : 'Monorepo Projects'
204+ } ) ;
205+
206+ return selectedItem ?. projectRoot ;
207+ }
208+
161209// Integrated common logic into a single function
162210async function generateDependencyGraph ( context : vscode . ExtensionContext , focusOnModule : boolean = false ) {
163211 // Use withProgress API to show a progress notification in the bottom right
@@ -175,65 +223,82 @@ async function generateDependencyGraph(context: vscode.ExtensionContext, focusOn
175223 // Use the first workspace folder as the root for searching
176224 const workspaceRoot = workspaceFolders [ 0 ] . uri . fsPath ;
177225
178- // Find the initial config file (used for full graph or as fallback)
179- progress . report ( { message : 'Finding ReScript config file...' } ) ;
180- const initialConfigFileUri = await findConfigFile ( workspaceRoot ) ;
181-
182- if ( token . isCancellationRequested ) return ;
183-
184- // If no config file is found anywhere, exit (should be caught by activationEvents)
185- if ( ! initialConfigFileUri ) {
186- vscode . window . showErrorMessage ( 'Could not find any bsconfig.json or rescript.json in the workspace (excluding node_modules).' ) ;
187- return ;
188- }
189-
190226 let projectRoot : string ;
191- let bsDir : string ;
192-
193- try {
194- let moduleName : string | undefined ;
227+ let moduleName : string | undefined ;
195228
229+ if ( focusOnModule ) {
196230 // --- Logic when focusing on a specific module ---
197- if ( focusOnModule ) {
198- progress . report ( { message : 'Getting module information...' } ) ;
199- if ( token . isCancellationRequested ) return ;
231+ progress . report ( { message : 'Getting module information...' } ) ;
232+ if ( token . isCancellationRequested ) return ;
200233
201- // Get module name (from editor or input)
202- moduleName = getCurrentModuleNameFromActiveEditor ( ) ;
203- if ( ! moduleName ) {
204- moduleName = await vscode . window . showInputBox ( {
205- prompt : 'Enter module name to focus on' ,
206- placeHolder : 'ModuleName'
207- } ) ;
208- }
209- if ( ! moduleName ) return ; // User cancelled
234+ // Get module name (from editor or input)
235+ moduleName = getCurrentModuleNameFromActiveEditor ( ) ;
236+ if ( ! moduleName ) {
237+ moduleName = await vscode . window . showInputBox ( {
238+ prompt : 'Enter module name to focus on' ,
239+ placeHolder : 'ModuleName'
240+ } ) ;
241+ }
242+ if ( ! moduleName ) return ; // User cancelled
243+
244+ // Find the source file for the target module
245+ progress . report ( { message : `Finding source file for ${ moduleName } ...` } ) ;
246+ const moduleInfo = await findModuleInProject ( moduleName ) ;
247+ if ( ! moduleInfo ) {
248+ vscode . window . showErrorMessage ( `Could not find the source file for module: ${ moduleName } ` ) ;
249+ return ;
250+ }
251+
252+ // Find the project root specific to this module's source file
253+ progress . report ( { message : `Finding project root for ${ moduleName } ...` } ) ;
254+ const moduleProjectRoot = await findProjectRootForFile ( moduleInfo . path , workspaceRoot ) ;
255+ if ( ! moduleProjectRoot ) {
256+ vscode . window . showErrorMessage ( `Could not determine the project root for module: ${ moduleName } (no bsconfig/rescript.json found in parent directories).` ) ;
257+ return ;
258+ }
210259
211- // Find the source file for the target module
212- progress . report ( { message : `Finding source file for ${ moduleName } ...` } ) ;
213- const moduleInfo = await findModuleInProject ( moduleName ) ;
214- if ( ! moduleInfo ) {
215- vscode . window . showErrorMessage ( `Could not find the source file for module: ${ moduleName } ` ) ;
260+ // Calculate bsDir based on the module's specific project root
261+ projectRoot = moduleProjectRoot ;
262+ } else {
263+ // Only check for monorepo and ask for project selection when not focusing on a specific module
264+ // Check if this is a monorepo with multiple projects
265+ progress . report ( { message : 'Checking workspace structure...' } ) ;
266+ const monorepoProjects = await detectMonorepoProjects ( workspaceRoot ) ;
267+
268+ // If it's a monorepo with multiple projects, ask user to select one
269+ if ( monorepoProjects . length > 1 ) {
270+ progress . report ( { message : 'Monorepo detected. Please select a project...' } ) ;
271+ const selectedProjectRoot = await selectMonorepoProject ( monorepoProjects ) ;
272+
273+ if ( ! selectedProjectRoot ) {
274+ // User cancelled the selection
216275 return ;
217276 }
218277
219- // Find the project root specific to this module's source file
220- progress . report ( { message : `Finding project root for ${ moduleName } ...` } ) ;
221- const moduleProjectRoot = await findProjectRootForFile ( moduleInfo . path , workspaceRoot ) ;
222- if ( ! moduleProjectRoot ) {
223- vscode . window . showErrorMessage ( `Could not determine the project root for module: ${ moduleName } (no bsconfig/rescript.json found in parent directories).` ) ;
278+ projectRoot = selectedProjectRoot ;
279+ } else {
280+ // Find the initial config file (used for full graph or as fallback)
281+ progress . report ( { message : 'Finding ReScript config file...' } ) ;
282+ const initialConfigFileUri = await findConfigFile ( workspaceRoot ) ;
283+
284+ if ( token . isCancellationRequested ) return ;
285+
286+ // If no config file is found anywhere, exit (should be caught by activationEvents)
287+ if ( ! initialConfigFileUri ) {
288+ vscode . window . showErrorMessage ( 'Could not find any bsconfig.json or rescript.json in the workspace (excluding node_modules).' ) ;
224289 return ;
225290 }
226291
227- // Calculate bsDir based on the module's specific project root
228- projectRoot = moduleProjectRoot ;
229- bsDir = path . join ( projectRoot , 'lib' , 'bs' ) ;
230-
231- } else {
232- // --- Logic for full dependency graph ---
233292 // Use the initially found config file's location
234293 projectRoot = path . dirname ( initialConfigFileUri . fsPath ) ;
235- bsDir = path . join ( projectRoot , 'lib' , 'bs' ) ;
236294 }
295+ }
296+
297+ let bsDir : string ;
298+
299+ try {
300+ // Calculate bsDir based on the determined project root
301+ bsDir = path . join ( projectRoot , 'lib' , 'bs' ) ;
237302
238303 // Check if the determined bsDir exists (common check)
239304 if ( ! fs . existsSync ( bsDir ) ) {
@@ -1209,7 +1274,7 @@ function showGraphWebview(context: vscode.ExtensionContext, jsonContent: string,
12091274 const fullArgs = [ ...cacheArgs , ...coreArgs ] ;
12101275
12111276 // Get JSON format data
1212- const jsonContent = await runRescriptDep ( cliPath , fullArgs , context ) ; // Pass context
1277+ const jsonContent = await runRescriptDep ( cliPath , fullArgs , context ) ;
12131278
12141279 if ( token . isCancellationRequested ) return ;
12151280
0 commit comments