@@ -3,6 +3,8 @@ import { glob } from "glob";
33import * as path from "path" ;
44import * as ts from "typescript" ;
55import {
6+ DeclarationFunctionNode ,
7+ DeclarationOrFunctionNode ,
68 IClassInfo ,
79 ICodebaseMap ,
810 IEnumInfo ,
@@ -17,8 +19,8 @@ import { ITypeScriptCodeMapper } from "../interfaces/ts.code.mapper.interface";
1719import { Result } from "../result" ;
1820
1921export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
20- public program : ts . Program | undefined ;
21- public typeChecker : ts . TypeChecker | undefined ;
22+ private program : ts . Program | undefined ;
23+ private typeChecker : ts . TypeChecker | undefined ;
2224
2325 constructor ( ) {
2426 this . initializeTypescriptProgram ( ) ;
@@ -28,7 +30,7 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
2830 * Initializes a TypeScript program by reading the TS configuration file and creating a new program instance.
2931 * This method sets up the program and type checker for further compilation and analysis.
3032 */
31- private initializeTypescriptProgram ( ) {
33+ private initializeTypescriptProgram ( ) : void {
3234 try {
3335 const rootDir : string = process . cwd ( ) ;
3436 const tsConfigPath : string = path . join ( rootDir , "tsconfig.json" ) ;
@@ -46,7 +48,7 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
4648 compilerOptions . options
4749 ) ;
4850
49- this . typeChecker = this . program . getTypeChecker ( ) ;
51+ this . typeChecker = this . getTypeChecker ( ) ;
5052 } catch ( error : any ) {
5153 logError ( error , "initializeTypescriptProgram" , "" ) ;
5254 throw Error ( error ) ;
@@ -86,6 +88,56 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
8688 }
8789 }
8890
91+ private aggregateFunctions (
92+ node : DeclarationFunctionNode ,
93+ sourceFile : ts . SourceFile ,
94+ info : IClassInfo | IModuleInfo
95+ ) : void {
96+ const functionInfo : IFunctionInfo | null =
97+ this . getFunctionDetails ( node , sourceFile ) ?. getValue ( ) ?? null ;
98+ if ( functionInfo ) {
99+ info ?. functions ?. push ( functionInfo ) ;
100+ }
101+ }
102+
103+ private aggergateProperties (
104+ node : ts . PropertyDeclaration ,
105+ sourceFile : ts . SourceFile ,
106+ info : IClassInfo | IModuleInfo
107+ ) {
108+ const propertyInfo = this . extractPropertyParameters (
109+ node ,
110+ sourceFile
111+ ) . getValue ( ) ;
112+ if ( propertyInfo ) {
113+ info ?. properties ?. push ( propertyInfo ) ;
114+ }
115+ }
116+
117+ private aggregateInterfaces (
118+ node : ts . InterfaceDeclaration ,
119+ sourceFile : ts . SourceFile ,
120+ info : IClassInfo | IModuleInfo
121+ ) {
122+ const interfaceInfo = this . extractInterfaceInfo (
123+ node ,
124+ sourceFile
125+ ) . getValue ( ) ;
126+ if ( interfaceInfo ) {
127+ info ?. interfaces ?. push ( interfaceInfo ) ;
128+ }
129+ }
130+
131+ private aggregateEnums (
132+ node : ts . EnumDeclaration ,
133+ sourceFile : ts . SourceFile ,
134+ info : IClassInfo | IModuleInfo
135+ ) {
136+ const enumInfo = this . extractEnumInfo ( node , sourceFile ) . getValue ( ) ;
137+ if ( enumInfo ) {
138+ info ?. enums ?. push ( enumInfo ) ;
139+ }
140+ }
89141 /**
90142 * Retrieves and processes child elements of a class declaration, extracting
91143 * relevant information about methods, properties, interfaces, and enums.
@@ -97,48 +149,30 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
97149 * @param classInfo The object to store extracted class information.
98150 */
99151 private processClassMembers (
100- node : ts . ClassDeclaration | ts . Node ,
152+ node : ts . ClassDeclaration ,
101153 sourceFile : ts . SourceFile ,
102154 info : IClassInfo | IModuleInfo ,
103155 member ?: ts . ClassElement
104156 ) : void {
105157 const currentElement = member ? member : node ;
106158 if (
107159 ts . isMethodDeclaration ( currentElement ) ||
108- ts . isFunctionDeclaration ( currentElement )
160+ ts . isFunctionDeclaration ( currentElement ) ||
161+ ts . isArrowFunction ( currentElement )
109162 ) {
110- const functionInfo : IFunctionInfo | null =
111- this . getFunctionDetails ( currentElement , sourceFile ) ?. getValue ( ) ?? null ;
112- if ( functionInfo ) {
113- info ?. functions ?. push ( functionInfo ) ;
114- }
163+ this . aggregateFunctions ( currentElement , sourceFile , info ) ;
115164 }
116165
117166 if ( ts . isPropertyDeclaration ( currentElement ) ) {
118- const propertyInfo = this . extractPropertyParameters (
119- currentElement ,
120- sourceFile
121- ) . getValue ( ) ;
122- if ( propertyInfo ) {
123- info ?. properties ?. push ( propertyInfo ) ;
124- }
167+ this . aggergateProperties ( currentElement , sourceFile , info ) ;
125168 }
126169
127170 if ( ts . isInterfaceDeclaration ( node ) ) {
128- const interfaceInfo = this . extractInterfaceInfo (
129- node ,
130- sourceFile
131- ) . getValue ( ) ;
132- if ( interfaceInfo ) {
133- info ?. interfaces ?. push ( interfaceInfo ) ;
134- }
171+ this . aggregateInterfaces ( node , sourceFile , info ) ;
135172 }
136173
137174 if ( ts . isEnumDeclaration ( node ) ) {
138- const enumInfo = this . extractEnumInfo ( node , sourceFile ) . getValue ( ) ;
139- if ( enumInfo ) {
140- info ?. enums ?. push ( enumInfo ) ;
141- }
175+ this . aggregateEnums ( node , sourceFile , info ) ;
142176 }
143177 }
144178
@@ -189,7 +223,24 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
189223 * @returns An array of function parameter objects.
190224 */
191225 extractFunctionParameters (
192- node : ts . FunctionDeclaration | ts . MethodDeclaration ,
226+ node : ts . FunctionDeclaration | ts . MethodDeclaration | ts . ArrowFunction ,
227+ sourceFile : ts . SourceFile
228+ ) : Result < IProperty [ ] > {
229+ const properties = node . parameters . map ( ( param ) => {
230+ const name = param . name . getText ( sourceFile ) ;
231+ const type = param . type
232+ ? this . getTypeAtLocation ( param ) . getValue ( )
233+ : undefined ;
234+ return {
235+ name,
236+ type,
237+ } ;
238+ } ) ;
239+ return Result . ok ( properties ) ;
240+ }
241+
242+ extractArrowFunctionParameters (
243+ node : ts . ArrowFunction ,
193244 sourceFile : ts . SourceFile
194245 ) : Result < IProperty [ ] > {
195246 const properties = node . parameters . map ( ( param ) => {
@@ -213,7 +264,7 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
213264 * @returns An object containing function details, or null if the node has no name.
214265 */
215266 getFunctionDetails (
216- node : ts . FunctionDeclaration | ts . MethodDeclaration ,
267+ node : ts . FunctionDeclaration | ts . MethodDeclaration | ts . ArrowFunction ,
217268 sourceFile : ts . SourceFile
218269 ) : Result < IFunctionInfo > | null {
219270 try {
@@ -222,11 +273,12 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
222273 }
223274
224275 const name : string = node . name . getText ( sourceFile ) ;
225- const content : string = this . getPrintedNode ( node , sourceFile ) ;
276+ const content : string = this . getFunctionNodeText ( node , sourceFile ) ;
226277 const parameters : IProperty [ ] = this . extractFunctionParameters (
227278 node ,
228279 sourceFile
229280 ) . getValue ( ) ;
281+
230282 const details = this . functionDetailsMapper (
231283 name ,
232284 content ,
@@ -254,7 +306,7 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
254306 name : string ,
255307 content : string ,
256308 parameters : IProperty [ ] ,
257- node : ts . FunctionDeclaration | ts . MethodDeclaration
309+ node : ts . FunctionDeclaration | ts . MethodDeclaration | ts . ArrowFunction
258310 ) {
259311 return {
260312 name,
@@ -272,12 +324,7 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
272324 * @returns A string representation of the function or method type, or undefined if type checking is unavailable.
273325 */
274326 getTypeAtLocation (
275- node :
276- | ts . FunctionDeclaration
277- | ts . MethodDeclaration
278- | ts . ParameterDeclaration
279- | ts . PropertyDeclaration
280- | ts . PropertySignature
327+ node : DeclarationOrFunctionNode
281328 ) : Result < string | undefined > {
282329 const type = this . typeChecker ?. typeToString (
283330 this . typeChecker . getTypeAtLocation ( node )
@@ -307,8 +354,8 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
307354 * @param sourceFile The source file that contains the node to be printed.
308355 * @returns A string representation of the given node.
309356 */
310- getPrintedNode (
311- node : ts . FunctionDeclaration | ts . MethodDeclaration ,
357+ getFunctionNodeText (
358+ node : ts . FunctionDeclaration | ts . MethodDeclaration | ts . ArrowFunction ,
312359 sourceFile : ts . SourceFile
313360 ) {
314361 const printer : ts . Printer = ts . createPrinter ( {
@@ -367,6 +414,51 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
367414 } ;
368415 }
369416
417+ /**
418+ * Retrieves a source file from the TypeScript program by its filename.
419+ *
420+ * @param fileName - The path to the source file to retrieve
421+ * @returns The SourceFile object if found, undefined otherwise
422+ */
423+ getSourceFile ( fileName : string ) : ts . SourceFile | undefined {
424+ return this . program ?. getSourceFile ( fileName ) ;
425+ }
426+
427+ /**
428+ * Gets an array of all root file names in the TypeScript program.
429+ * Root files are the entry points specified in the tsconfig.json or passed to the compiler.
430+ *
431+ * @returns A readonly array of file paths, or undefined if the program is not initialized
432+ */
433+ getRootFileNames ( ) : readonly string [ ] | undefined {
434+ return this . program ?. getRootFileNames ( ) ;
435+ }
436+
437+ /**
438+ * Returns the current TypeScript program instance.
439+ * The program object represents the entire TypeScript project and provides
440+ * access to the compiler's internal state.
441+ *
442+ * @returns The TypeScript Program object, or undefined if not initialized
443+ */
444+ getProgram ( ) : ts . Program | undefined {
445+ return this . program ;
446+ }
447+
448+ /**
449+ * Retrieves the TypeChecker instance from the current program.
450+ * The TypeChecker is responsible for type analysis and provides
451+ * APIs for querying type information.
452+ *
453+ * @returns The TypeScript TypeChecker object, or undefined if the program is not initialized
454+ * @remarks This method creates a new type checker instance each time it's called,
455+ * consider caching the result if multiple calls are needed
456+ */
457+ getTypeChecker ( ) : ts . TypeChecker | undefined {
458+ const program = this . getProgram ( ) ;
459+ return program ? program . getTypeChecker ( ) : undefined ;
460+ }
461+
370462 /**
371463 * Builds a hierarchical map of the codebase by traversing TypeScript files
372464 * and extracting module and class information.
@@ -380,7 +472,7 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
380472 const tsFiles : string [ ] = await this . getTsFiles ( ) ;
381473 tsFiles . forEach ( ( filePath ) => {
382474 const moduleRalativePath = path . relative ( rootDir , filePath ) ;
383- const sourceFile = this . program ?. getSourceFile ( filePath ) ;
475+ const sourceFile = this . getSourceFile ( filePath ) ;
384476
385477 if ( ! sourceFile ) {
386478 throw Error ( `No source file found for ${ filePath } ` ) ;
@@ -399,8 +491,28 @@ export class TypeScriptCodeMapper implements ITypeScriptCodeMapper {
399491 if ( classInfo ) {
400492 moduleInfo ?. classes ?. push ( classInfo ) ;
401493 }
494+ this . processClassMembers ( node , sourceFile , moduleInfo ) ;
495+ }
496+
497+ if (
498+ ts . isMethodDeclaration ( node ) ||
499+ ts . isFunctionDeclaration ( node ) ||
500+ ( ts . isVariableDeclaration ( node ) && ts . isArrowFunction ( node ) )
501+ ) {
502+ this . aggregateFunctions ( node , sourceFile , moduleInfo ) ;
503+ }
504+
505+ if ( ts . isPropertyDeclaration ( node ) ) {
506+ this . aggergateProperties ( node , sourceFile , moduleInfo ) ;
507+ }
508+
509+ if ( ts . isInterfaceDeclaration ( node ) ) {
510+ this . aggregateInterfaces ( node , sourceFile , moduleInfo ) ;
511+ }
512+
513+ if ( ts . isEnumDeclaration ( node ) ) {
514+ this . aggregateEnums ( node , sourceFile , moduleInfo ) ;
402515 }
403- this . processClassMembers ( node , sourceFile , moduleInfo ) ;
404516 codebaseMap [ repoNames ] . modules [ moduleRalativePath ] = moduleInfo ;
405517 } ) ;
406518 } ) ;
0 commit comments