11import fs from 'fs' ;
22import path from 'path' ;
3+ import { XMLParser } from 'fast-xml-parser' ;
34import { techMap } from './techMap' ;
45import simpleIconsHex from './simple-icons-hex.json' ;
56import { generateMarkdown , copyAssets } from './output' ;
@@ -37,7 +38,7 @@ function getPackageJson(projectPath: string) {
3738 const content = fs . readFileSync ( pkgPathUnderscore , 'utf-8' ) ;
3839 return JSON . parse ( content ) ;
3940 } catch ( e : any ) {
40- throw new Error ( `Failed to read _package.json: ${ e . message } ` ) ;
41+ console . warn ( `Failed to read _package.json: ${ e . message } ` ) ;
4142 }
4243 }
4344
@@ -47,13 +48,60 @@ function getPackageJson(projectPath: string) {
4748 const content = fs . readFileSync ( pkgPath , 'utf-8' ) ;
4849 return JSON . parse ( content ) ;
4950 } catch ( e : any ) {
50- throw new Error ( `Failed to read package.json: ${ e . message } ` ) ;
51+ console . warn ( `Failed to read package.json: ${ e . message } ` ) ;
5152 }
5253 }
5354
5455 return null ;
5556}
5657
58+ // Helper to look for pom.xml or _pom.xml
59+ function getPomXml ( projectPath : string ) {
60+ const pomPath = path . join ( projectPath , 'pom.xml' ) ;
61+ const pomPathUnderscore = path . join ( projectPath , '_pom.xml' ) ;
62+
63+ // Check if we are inside public/stackscan
64+ const isInsideStackScanDir = projectPath . includes ( path . join ( 'public' , 'stackscan' ) ) ;
65+
66+ // Priority 1: Check for active pom.xml and rename it
67+ if ( fs . existsSync ( pomPath ) && isInsideStackScanDir ) {
68+ try {
69+ console . log ( `Renaming ${ pomPath } to ${ pomPathUnderscore } ` ) ;
70+ fs . renameSync ( pomPath , pomPathUnderscore ) ;
71+ } catch ( e : any ) {
72+ console . warn ( `Failed to rename pom.xml to _pom.xml: ${ e . message } ` ) ;
73+ }
74+ }
75+
76+ // Read _pom.xml or pom.xml
77+ let xmlContent : string | null = null ;
78+ if ( fs . existsSync ( pomPathUnderscore ) ) {
79+ try {
80+ xmlContent = fs . readFileSync ( pomPathUnderscore , 'utf-8' ) ;
81+ } catch ( e : any ) {
82+ console . warn ( `Failed to read _pom.xml: ${ e . message } ` ) ;
83+ }
84+ } else if ( fs . existsSync ( pomPath ) ) {
85+ try {
86+ xmlContent = fs . readFileSync ( pomPath , 'utf-8' ) ;
87+ } catch ( e : any ) {
88+ console . warn ( `Failed to read pom.xml: ${ e . message } ` ) ;
89+ }
90+ }
91+
92+ if ( xmlContent ) {
93+ try {
94+ const parser = new XMLParser ( ) ;
95+ return parser . parse ( xmlContent ) ;
96+ } catch ( e : any ) {
97+ console . warn ( `Failed to parse XML: ${ e . message } ` ) ;
98+ }
99+ }
100+
101+ return null ;
102+ }
103+
104+
57105const CATEGORY_PRIORITY = [
58106 "language" ,
59107 "framework" ,
@@ -112,12 +160,34 @@ interface SyncOptions {
112160
113161async function analyzeProject ( projectPath : string , options : SyncOptions ) : Promise < any [ ] > {
114162 const pkg = getPackageJson ( projectPath ) ;
115- if ( ! pkg ) {
116- throw new Error ( `No package.json or _package.json found at ${ projectPath } ` ) ;
163+ const pom = getPomXml ( projectPath ) ;
164+
165+ if ( ! pkg && ! pom ) {
166+ throw new Error ( `No package.json or pom.xml found at ${ projectPath } ` ) ;
117167 }
118168
119169 // 1. Detect Tech
120- const allDeps = { ...pkg . dependencies , ...pkg . devDependencies } ;
170+ const allDeps : Record < string , any > = { } ;
171+
172+ // Process package.json
173+ if ( pkg ) {
174+ Object . assign ( allDeps , pkg . dependencies , pkg . devDependencies ) ;
175+ }
176+
177+ // Process pom.xml
178+ if ( pom && pom . project && pom . project . dependencies && pom . project . dependencies . dependency ) {
179+ let deps = pom . project . dependencies . dependency ;
180+ if ( ! Array . isArray ( deps ) ) {
181+ deps = [ deps ] ;
182+ }
183+
184+ deps . forEach ( ( d : any ) => {
185+ // Map groupId:artifactId and just artifactId
186+ if ( d . artifactId ) allDeps [ d . artifactId ] = "latest" ;
187+ if ( d . groupId && d . artifactId ) allDeps [ `${ d . groupId } :${ d . artifactId } ` ] = "latest" ;
188+ } ) ;
189+ }
190+
121191 const detectedTechs : any [ ] = [ ] ;
122192
123193 Object . keys ( allDeps ) . forEach ( dep => {
@@ -261,8 +331,12 @@ async function scan(targetPath?: string | object, optionsOrUndefined?: SyncOptio
261331
262332 for ( const dir of projectDirs ) {
263333 const projectPath = path . join ( BASE_DIR , dir . name ) ;
334+
335+ // Check for package.json OR pom.xml (or their underscored variants)
336+ const hasPackageJson = fs . existsSync ( path . join ( projectPath , 'package.json' ) ) || fs . existsSync ( path . join ( projectPath , '_package.json' ) ) ;
337+ const hasPomXml = fs . existsSync ( path . join ( projectPath , 'pom.xml' ) ) || fs . existsSync ( path . join ( projectPath , '_pom.xml' ) ) ;
264338
265- if ( fs . existsSync ( path . join ( projectPath , 'package.json' ) ) ) {
339+ if ( hasPackageJson || hasPomXml ) {
266340 try {
267341 const techsWithUrls = await analyzeProject ( projectPath , options ) ;
268342
@@ -288,7 +362,7 @@ async function scan(targetPath?: string | object, optionsOrUndefined?: SyncOptio
288362 console . error ( `❌ Error processing ${ dir . name } :` , err . message ) ;
289363 }
290364 } else {
291- console . warn ( `⚠️ Skipping "${ dir . name } ": No package.json found.` ) ;
365+ console . warn ( `⚠️ Skipping "${ dir . name } ": No package.json or pom.xml found.` ) ;
292366 }
293367 }
294368
0 commit comments