@@ -4,19 +4,78 @@ import * as fs from 'fs';
44import { Repository , Node , Relation , Identity , Function } from '../types/uniast' ;
55import { ModuleParser } from './ModuleParser' ;
66import { TsConfigCache } from '../utils/tsconfig-cache' ;
7+ import { MonorepoUtils } from '../utils/monorepo' ;
78
89export class RepositoryParser {
9- private project : Project ;
10- private moduleParser : ModuleParser ;
10+ private project ? : Project ;
11+ private moduleParser ? : ModuleParser ;
1112 private tsConfigCache : TsConfigCache ;
13+ private projectRoot : string ;
14+ private tsConfigPath ?: string ;
1215
1316 constructor ( projectRoot : string , tsConfigPath ?: string ) {
1417 this . tsConfigCache = TsConfigCache . getInstance ( ) ;
18+ this . projectRoot = projectRoot ;
19+ this . tsConfigPath = tsConfigPath ;
20+ }
1521
22+ async parseRepository ( repoPath : string , options : { loadExternalSymbols ?: boolean , noDist ?: boolean , srcPatterns ?: string [ ] } = { } ) : Promise < Repository > {
23+ const absolutePath = path . resolve ( repoPath ) ;
1624
17- let configPath = path . join ( projectRoot , 'tsconfig.json' ) ;
25+ const repository : Repository = {
26+ ASTVersion : "v0.1.3" ,
27+ id : path . basename ( absolutePath ) ,
28+ Modules : { } ,
29+ Graph : { }
30+ } ;
31+
32+ const isMonorepo = MonorepoUtils . isMonorepo ( absolutePath ) ;
33+
34+ if ( isMonorepo ) {
35+ const packages = MonorepoUtils . getMonorepoPackages ( absolutePath ) ;
36+ console . log ( `Monorepo detected. Found ${ packages . length } packages.` ) ;
37+
38+ for ( const pkg of packages ) {
39+ const packageTsConfigPath = path . join ( pkg . absolutePath , 'tsconfig.json' ) ;
40+ try {
41+ let project : Project ;
42+ if ( fs . existsSync ( packageTsConfigPath ) ) {
43+ console . log ( `Parsing package ${ pkg . name || pkg . path } with tsconfig ${ packageTsConfigPath } ` ) ;
44+ project = new Project ( {
45+ tsConfigFilePath : packageTsConfigPath ,
46+ compilerOptions : {
47+ allowJs : true ,
48+ skipLibCheck : true ,
49+ forceConsistentCasingInFileNames : true
50+ }
51+ } ) ;
52+ } else {
53+ console . log ( `No tsconfig.json found for package ${ pkg . name || pkg . path } , using default configuration.` ) ;
54+ project = this . createProjectWithDefaultConfig ( ) ;
55+ }
56+
57+ const moduleParser = new ModuleParser ( project , this . projectRoot ) ;
58+ const module = await moduleParser . parseModule ( pkg . absolutePath , pkg . path , options ) ;
59+ repository . Modules [ module . Name ] = module ;
60+ } catch ( error ) {
61+ console . warn ( `Failed to parse package ${ pkg . name || pkg . path } :` , error ) ;
62+ }
63+ }
64+ } else {
65+ console . log ( 'Single project detected.' ) ;
66+ this . project = this . createProjectForSingleRepo ( this . projectRoot , this . tsConfigPath ) ;
67+ this . moduleParser = new ModuleParser ( this . project , this . projectRoot ) ;
68+ const module = await this . moduleParser . parseModule ( absolutePath , '.' , options ) ;
69+ repository . Modules [ module . Name ] = module ;
70+ }
71+
72+ this . buildGlobalGraph ( repository ) ;
73+ return repository ;
74+ }
75+
76+ private createProjectForSingleRepo ( projectRoot : string , tsConfigPath ?: string ) : Project {
77+ let configPath = path . join ( projectRoot , 'tsconfig.json' ) ;
1878
19- // If a custom tsconfig path is provided, use it
2079 if ( tsConfigPath ) {
2180 let absoluteTsConfigPath = tsConfigPath ;
2281 if ( ! path . isAbsolute ( absoluteTsConfigPath ) ) {
@@ -27,8 +86,7 @@ export class RepositoryParser {
2786 }
2887
2988 if ( fs . existsSync ( configPath ) ) {
30- // if tsconfig.json exists, use it to configure the project
31- this . project = new Project ( {
89+ const project = new Project ( {
3290 tsConfigFilePath : configPath ,
3391 compilerOptions : {
3492 allowJs : true ,
@@ -62,8 +120,7 @@ export class RepositoryParser {
62120 console . warn ( "parse tsconfig warning:" , err . messageText )
63121 } ) ;
64122 }
65- this . project . addSourceFilesAtPaths ( parsedConfig . fileNames ) ;
66- // Get references
123+ project . addSourceFilesAtPaths ( parsedConfig . fileNames ) ;
67124 const references = parsedConfig . projectReferences ;
68125 if ( ! references ) {
69126 continue ;
@@ -78,63 +135,43 @@ export class RepositoryParser {
78135 }
79136 }
80137 }
138+ return project ;
81139 } else {
82- // if tsconfig.json does not exist, use default configuration
83- this . project = new Project ( {
84- compilerOptions : {
85- target : 99 ,
86- module : 1 ,
87- allowJs : true ,
88- checkJs : false ,
89- skipLibCheck : true ,
90- skipDefaultLibCheck : true ,
91- strict : false ,
92- noImplicitAny : false ,
93- strictNullChecks : false ,
94- strictFunctionTypes : false ,
95- strictBindCallApply : false ,
96- strictPropertyInitialization : false ,
97- noImplicitReturns : false ,
98- noFallthroughCasesInSwitch : false ,
99- noUncheckedIndexedAccess : false ,
100- noImplicitOverride : false ,
101- noPropertyAccessFromIndexSignature : false ,
102- allowUnusedLabels : false ,
103- allowUnreachableCode : false ,
104- exactOptionalPropertyTypes : false ,
105- noImplicitThis : false ,
106- alwaysStrict : false ,
107- noImplicitUseStrict : false ,
108- forceConsistentCasingInFileNames : true
109- }
110- } ) ;
140+ return this . createProjectWithDefaultConfig ( ) ;
111141 }
112-
113- this . moduleParser = new ModuleParser ( this . project , projectRoot ) ;
114142 }
115143
116-
117- async parseRepository ( repoPath : string , options : { loadExternalSymbols ?: boolean , noDist ?: boolean , srcPatterns ?: string [ ] } = { } ) : Promise < Repository > {
118- const absolutePath = path . resolve ( repoPath ) ;
119-
120- const repository : Repository = {
121- ASTVersion : "v0.1.3" ,
122- id : path . basename ( absolutePath ) ,
123- Modules : { } ,
124- Graph : { }
125- } ;
126-
127- // Parse main module only
128- const mainModule = await this . moduleParser . parseModule ( absolutePath , '.' , options ) ;
129- repository . Modules [ mainModule . Name ] = mainModule ;
130-
131- // Build global symbol graph
132- this . buildGlobalGraph ( repository ) ;
133-
134- return repository ;
144+ private createProjectWithDefaultConfig ( ) : Project {
145+ return new Project ( {
146+ compilerOptions : {
147+ target : 99 ,
148+ module : 1 ,
149+ allowJs : true ,
150+ checkJs : false ,
151+ skipLibCheck : true ,
152+ skipDefaultLibCheck : true ,
153+ strict : false ,
154+ noImplicitAny : false ,
155+ strictNullChecks : false ,
156+ strictFunctionTypes : false ,
157+ strictBindCallApply : false ,
158+ strictPropertyInitialization : false ,
159+ noImplicitReturns : false ,
160+ noFallthroughCasesInSwitch : false ,
161+ noUncheckedIndexedAccess : false ,
162+ noImplicitOverride : false ,
163+ noPropertyAccessFromIndexSignature : false ,
164+ allowUnusedLabels : false ,
165+ allowUnreachableCode : false ,
166+ exactOptionalPropertyTypes : false ,
167+ noImplicitThis : false ,
168+ alwaysStrict : false ,
169+ noImplicitUseStrict : false ,
170+ forceConsistentCasingInFileNames : true
171+ }
172+ } ) ;
135173 }
136174
137-
138175 private buildGlobalGraph ( repository : Repository ) : void {
139176 // First pass: Create all nodes from functions, types, and variables
140177 for ( const [ , module ] of Object . entries ( repository . Modules ) ) {
0 commit comments