22// Licensed under the MIT license.
33
44import * as fs from 'fs' ;
5- import * as path from 'path' ;
65import * as semver from 'semver' ;
6+ import * as glob from 'glob' ;
7+ import { promisify } from 'util' ;
8+
9+ const globAsync = promisify ( glob ) ;
710import { Uri } from 'vscode' ;
811import { Jdtls } from "../java/jdtls" ;
912import { NodeKind , type INodeData } from "../java/nodeData" ;
@@ -182,10 +185,25 @@ const MAVEN_CONTAINER_PATH = "org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER";
182185const GRADLE_CONTAINER_PATH = "org.eclipse.buildship.core.gradleclasspathcontainer" ;
183186
184187/**
185- * Parse direct dependencies from pom.xml file.
186- * Also checks parent pom.xml for multi-module projects.
188+ * Find all pom.xml files in a directory using glob
187189 */
188- function parseDirectDependenciesFromPom ( pomPath : string ) : Set < string > {
190+ async function findAllPomFiles ( dir : string ) : Promise < string [ ] > {
191+ try {
192+ return await globAsync ( '**/pom.xml' , {
193+ cwd : dir ,
194+ absolute : true ,
195+ nodir : true ,
196+ ignore : [ '**/node_modules/**' , '**/target/**' , '**/.git/**' , '**/.idea/**' , '**/.vscode/**' ]
197+ } ) ;
198+ } catch {
199+ return [ ] ;
200+ }
201+ }
202+
203+ /**
204+ * Parse dependencies from a single pom.xml file
205+ */
206+ function parseDependenciesFromSinglePom ( pomPath : string ) : Set < string > {
189207 const directDeps = new Set < string > ( ) ;
190208 try {
191209 const pomContent = fs . readFileSync ( pomPath , 'utf-8' ) ;
@@ -205,23 +223,51 @@ function parseDirectDependenciesFromPom(pomPath: string): Set<string> {
205223 directDeps . add ( `${ groupId } :${ artifactId } ` ) ;
206224 }
207225 }
208-
209- // Check for parent pom in multi-module projects
210- const parentPomPath = path . join ( path . dirname ( pomPath ) , '..' , 'pom.xml' ) ;
211- if ( fs . existsSync ( parentPomPath ) ) {
212- const parentDeps = parseDirectDependenciesFromPom ( parentPomPath ) ;
213- parentDeps . forEach ( dep => directDeps . add ( dep ) ) ;
214- }
215226 } catch {
216227 // If we can't read the pom, return empty set
217228 }
218229 return directDeps ;
219230}
220231
221232/**
222- * Parse direct dependencies from build.gradle or build.gradle.kts file
233+ * Parse direct dependencies from all pom.xml files in the project.
234+ * Finds all pom.xml files starting from the project root and parses them to collect dependencies.
235+ */
236+ async function parseDirectDependenciesFromPom ( projectPath : string ) : Promise < Set < string > > {
237+ const directDeps = new Set < string > ( ) ;
238+
239+ // Find all pom.xml files in the project starting from the project root
240+ const allPomFiles = await findAllPomFiles ( projectPath ) ;
241+
242+ // Parse each pom.xml and collect dependencies
243+ for ( const pom of allPomFiles ) {
244+ const deps = parseDependenciesFromSinglePom ( pom ) ;
245+ deps . forEach ( dep => directDeps . add ( dep ) ) ;
246+ }
247+
248+ return directDeps ;
249+ }
250+
251+ /**
252+ * Find all Gradle build files in a directory using glob
223253 */
224- function parseDirectDependenciesFromGradle ( gradlePath : string ) : Set < string > {
254+ async function findAllGradleFiles ( dir : string ) : Promise < string [ ] > {
255+ try {
256+ return await globAsync ( '**/{build.gradle,build.gradle.kts}' , {
257+ cwd : dir ,
258+ absolute : true ,
259+ nodir : true ,
260+ ignore : [ '**/node_modules/**' , '**/build/**' , '**/.git/**' , '**/.idea/**' , '**/.vscode/**' , '**/.gradle/**' ]
261+ } ) ;
262+ } catch {
263+ return [ ] ;
264+ }
265+ }
266+
267+ /**
268+ * Parse dependencies from a single Gradle build file
269+ */
270+ function parseDependenciesFromSingleGradle ( gradlePath : string ) : Set < string > {
225271 const directDeps = new Set < string > ( ) ;
226272 try {
227273 const gradleContent = fs . readFileSync ( gradlePath , 'utf-8' ) ;
@@ -257,47 +303,22 @@ function parseDirectDependenciesFromGradle(gradlePath: string): Set<string> {
257303}
258304
259305/**
260- * Find the build file (pom.xml or build.gradle) for a project
261- */
262- function findBuildFile ( projectUri : string | undefined ) : { path : string ; type : 'maven' | 'gradle' } | null {
263- if ( ! projectUri ) {
264- return null ;
265- }
266- try {
267- const projectPath = Uri . parse ( projectUri ) . fsPath ;
268-
269- // Check for Maven
270- const pomPath = path . join ( projectPath , 'pom.xml' ) ;
271- if ( fs . existsSync ( pomPath ) ) {
272- return { path : pomPath , type : 'maven' } ;
273- }
274-
275- // Check for Gradle Kotlin DSL
276- const gradleKtsPath = path . join ( projectPath , 'build.gradle.kts' ) ;
277- if ( fs . existsSync ( gradleKtsPath ) ) {
278- return { path : gradleKtsPath , type : 'gradle' } ;
279- }
280-
281- // Check for Gradle Groovy DSL
282- const gradlePath = path . join ( projectPath , 'build.gradle' ) ;
283- if ( fs . existsSync ( gradlePath ) ) {
284- return { path : gradlePath , type : 'gradle' } ;
285- }
286- } catch {
287- // Ignore errors
288- }
289- return null ;
290- }
291-
292- /**
293- * Parse direct dependencies from build file (Maven or Gradle)
306+ * Parse direct dependencies from all Gradle build files in the project.
307+ * Finds all build.gradle and build.gradle.kts files and parses them to collect dependencies.
294308 */
295- function parseDirectDependencies ( buildFile : { path : string ; type : 'maven' | 'gradle' } ) : Set < string > {
296- if ( buildFile . type === 'maven' ) {
297- return parseDirectDependenciesFromPom ( buildFile . path ) ;
298- } else {
299- return parseDirectDependenciesFromGradle ( buildFile . path ) ;
309+ async function parseDirectDependenciesFromGradle ( projectPath : string ) : Promise < Set < string > > {
310+ const directDeps = new Set < string > ( ) ;
311+
312+ // Find all Gradle build files in the project
313+ const allGradleFiles = await findAllGradleFiles ( projectPath ) ;
314+
315+ // Parse each gradle file and collect dependencies
316+ for ( const gradleFile of allGradleFiles ) {
317+ const deps = parseDependenciesFromSingleGradle ( gradleFile ) ;
318+ deps . forEach ( dep => directDeps . add ( dep ) ) ;
300319 }
320+
321+ return directDeps ;
301322}
302323
303324async function getDirectDependencies ( projectNode : INodeData ) : Promise < PackageDescription [ ] > {
@@ -308,9 +329,12 @@ async function getDirectDependencies(projectNode: INodeData): Promise<PackageDes
308329 ( x . path ?. startsWith ( MAVEN_CONTAINER_PATH ) || x . path ?. startsWith ( GRADLE_CONTAINER_PATH ) )
309330 ) ;
310331
311- // Get direct dependency identifiers from build file
312- const buildFile = findBuildFile ( projectNode . uri ) ;
313- const directDependencyIds = buildFile ? parseDirectDependencies ( buildFile ) : null ;
332+ if ( dependencyContainers . length === 0 ) {
333+ return [ ] ;
334+ }
335+ // Determine build type from dependency containers
336+ const isMaven = dependencyContainers . some ( x => x . path ?. startsWith ( MAVEN_CONTAINER_PATH ) ) ;
337+
314338
315339 const allPackages = await Promise . allSettled (
316340 dependencyContainers . map ( async ( packageContainer ) => {
@@ -336,10 +360,39 @@ async function getDirectDependencies(projectNode: INodeData): Promise<PackageDes
336360
337361 let dependencies = fulfilled . map ( x => x . value ) . flat ( ) ;
338362
363+ if ( ! dependencies ) {
364+ sendInfo ( "" , {
365+ operationName : "java.dependency.assessmentManager.getDirectDependencies.noDependencyInfo" ,
366+ buildType : isMaven ? "maven" : "gradle" ,
367+ } ) ;
368+ return [ ] ;
369+ }
370+ // Get direct dependency identifiers from build files
371+ let directDependencyIds : Set < string > | null = null ;
372+ if ( projectNode . uri && dependencyContainers . length > 0 ) {
373+ try {
374+ const projectPath = Uri . parse ( projectNode . uri ) . fsPath ;
375+ if ( isMaven ) {
376+ directDependencyIds = await parseDirectDependenciesFromPom ( projectPath ) ;
377+ } else {
378+ directDependencyIds = await parseDirectDependenciesFromGradle ( projectPath ) ;
379+ }
380+ } catch {
381+ // Ignore errors
382+ }
383+ }
384+
385+ if ( ! directDependencyIds ) {
386+ sendInfo ( "" , {
387+ operationName : "java.dependency.assessmentManager.getDirectDependencies.noDirectDependencyInfo" ,
388+ buildType : isMaven ? "maven" : "gradle" ,
389+ } ) ;
390+ return [ ] ;
391+ }
339392 // Filter to only direct dependencies if we have build file info
340393 if ( directDependencyIds && directDependencyIds . size > 0 ) {
341394 dependencies = dependencies . filter ( pkg =>
342- directDependencyIds . has ( `${ pkg . groupId } :${ pkg . artifactId } ` )
395+ directDependencyIds ! . has ( `${ pkg . groupId } :${ pkg . artifactId } ` )
343396 ) ;
344397 }
345398
0 commit comments