11import type { ScannedFile } from "./fileScanner.js" ;
22import { isArchitectureSource } from "./sourceScope.js" ;
33
4- export type Framework = "nextjs" | "express" | "unknown" ;
4+ export type Framework = "nextjs" | "react" | " express" | "unknown" ;
55
66export function detectFramework ( files : ScannedFile [ ] ) : Framework {
7- const packageJson = files . find ( ( file ) => file . path === "package.json" ) ;
8- const dependencies = packageJson ? readDependencies ( packageJson . content ) : { } ;
7+ const dependencies = readAllDependencies ( files ) ;
98 const sourceFiles = files . filter ( ( file ) => isArchitectureSource ( file . path ) ) ;
109
1110 if (
1211 "next" in dependencies
13- || sourceFiles . some ( ( file ) => / ^ (?: s r c \/ ) ? (?: a p p | p a g e s ) \/ / . test ( file . path ) )
12+ || files . some ( ( file ) => / ^ n e x t \. c o n f i g \. [ c m ] ? [ j t ] s $ / . test ( file . path ) )
13+ || sourceFiles . some ( ( file ) =>
14+ / ^ (?: s r c \/ ) ? a p p \/ (?: .+ \/ ) ? (?: p a g e | l a y o u t | r o u t e ) \. [ j t ] s x ? $ / . test ( file . path )
15+ || / ^ (?: s r c \/ ) ? p a g e s \/ (?: _ a p p | _ d o c u m e n t | a p i \/ ) / . test ( file . path )
16+ )
1417 ) {
1518 return "nextjs" ;
1619 }
@@ -22,9 +25,31 @@ export function detectFramework(files: ScannedFile[]): Framework {
2225 return "express" ;
2326 }
2427
28+ const hasReactRuntime = "react-dom" in dependencies
29+ || "react-scripts" in dependencies
30+ || "@vitejs/plugin-react" in dependencies
31+ || "@vitejs/plugin-react-swc" in dependencies ;
32+ const hasReactSource = sourceFiles . some ( ( file ) =>
33+ / \. [ j t ] s x $ / . test ( file . path )
34+ || / (?: f r o m \s + [ " ' ] r e a c t [ " ' ] | f r o m \s + [ " ' ] r e a c t - d o m (?: \/ c l i e n t ) ? [ " ' ] | r e q u i r e \( [ " ' ] r e a c t [ " ' ] \) ) / . test ( file . content )
35+ ) ;
36+
37+ if ( "react" in dependencies && hasReactRuntime && hasReactSource ) {
38+ return "react" ;
39+ }
40+
2541 return "unknown" ;
2642}
2743
44+ function readAllDependencies ( files : ScannedFile [ ] ) : Record < string , string > {
45+ return files
46+ . filter ( ( file ) => file . path . endsWith ( "package.json" ) )
47+ . reduce ( ( dependencies , file ) => ( {
48+ ...dependencies ,
49+ ...readDependencies ( file . content )
50+ } ) , { } as Record < string , string > ) ;
51+ }
52+
2853function readDependencies ( content : string ) : Record < string , string > {
2954 try {
3055 const parsed = JSON . parse ( content ) as {
0 commit comments