@@ -105,6 +105,12 @@ export class TypeParser {
105105 const content = cls . getFullText ( ) ;
106106 const isExported = cls . isExported ( ) || cls . isDefaultExport ( ) || ( sym === this . defaultExported && sym !== undefined ) ;
107107
108+ // Collect type parameter names
109+ const typeParamNames = new Set < string > ( ) ;
110+ for ( const typeParam of cls . getTypeParameters ( ) ) {
111+ typeParamNames . add ( typeParam . getName ( ) ) ;
112+ }
113+
108114 // Parse methods
109115 // eslint-disable-next-line @typescript-eslint/no-explicit-any
110116 const methods : Record < string , any > = { } ;
@@ -128,7 +134,7 @@ export class TypeParser {
128134 const typeNodes = clause . getTypeNodes ( ) ;
129135
130136 for ( const typeNode of typeNodes ) {
131- const dependencies = this . extractTypeDependencies ( typeNode , moduleName , packagePath ) ;
137+ const dependencies = this . extractTypeDependencies ( typeNode , moduleName , packagePath , typeParamNames ) ;
132138 if ( clauseType === SyntaxKind . ImplementsKeyword ) {
133139 implementsInterfaces . push ( ...dependencies ) ;
134140 } else if ( clauseType === SyntaxKind . ExtendsKeyword ) {
@@ -170,6 +176,12 @@ export class TypeParser {
170176 const content = iface . getFullText ( ) ;
171177 const isExported = iface . isExported ( ) || iface . isDefaultExport ( ) || ( sym === this . defaultExported && sym !== undefined ) ;
172178
179+ // Collect type parameter names
180+ const typeParamNames = new Set < string > ( ) ;
181+ for ( const typeParam of iface . getTypeParameters ( ) ) {
182+ typeParamNames . add ( typeParam . getName ( ) ) ;
183+ }
184+
173185 // Parse methods
174186 // eslint-disable-next-line @typescript-eslint/no-explicit-any
175187 const methods : Record < string , any > = { } ;
@@ -190,7 +202,7 @@ export class TypeParser {
190202 if ( clause . getToken ( ) === SyntaxKind . ExtendsKeyword ) {
191203 const typeNodes = clause . getTypeNodes ( ) ;
192204 for ( const typeNode of typeNodes ) {
193- const dependencies = this . extractTypeDependencies ( typeNode , moduleName , packagePath ) ;
205+ const dependencies = this . extractTypeDependencies ( typeNode , moduleName , packagePath , typeParamNames ) ;
194206 extendsInterfaces . push ( ...dependencies ) ;
195207 }
196208 }
@@ -229,11 +241,17 @@ export class TypeParser {
229241 const content = typeAlias . getFullText ( ) ;
230242 const isExported = typeAlias . isExported ( ) || typeAlias . isDefaultExport ( ) || ( sym === this . defaultExported && sym !== undefined ) ;
231243
244+ // Collect type parameter names
245+ const typeParamNames = new Set < string > ( ) ;
246+ for ( const typeParam of typeAlias . getTypeParameters ( ) ) {
247+ typeParamNames . add ( typeParam . getName ( ) ) ;
248+ }
249+
232250 // Extract type dependencies from the type alias
233251 const typeDependencies : Dependency [ ] = [ ] ;
234252 const typeNode = typeAlias . getTypeNode ( ) ;
235253 if ( typeNode ) {
236- const dependencies = this . extractTypeDependencies ( typeNode , moduleName , packagePath ) ;
254+ const dependencies = this . extractTypeDependencies ( typeNode , moduleName , packagePath , typeParamNames ) ;
237255 typeDependencies . push ( ...dependencies ) ;
238256 }
239257
@@ -290,7 +308,7 @@ export class TypeParser {
290308 * This handles union types, intersection types, generics, arrays, etc.
291309 * Uses SymbolResolver for consistent dependency resolution, similar to extractTypeReferences
292310 */
293- private extractTypeDependencies ( typeNode : TypeNode , moduleName : string , packagePath : string ) : Dependency [ ] {
311+ private extractTypeDependencies ( typeNode : TypeNode , moduleName : string , packagePath : string , typeParamNames ?: Set < string > ) : Dependency [ ] {
294312 const dependencies : Dependency [ ] = [ ] ;
295313 const visited = new Set < string > ( ) ;
296314
@@ -311,24 +329,29 @@ export class TypeParser {
311329 if ( symbol ) {
312330 const [ resolvedSymbol , resolvedRealSymbol ] = this . symbolResolver . resolveSymbol ( symbol , typeNode ) ;
313331 if ( resolvedSymbol && ! resolvedSymbol . isExternal ) {
314- const decls = resolvedRealSymbol ?. getDeclarations ( ) || [ ] ;
315- if ( decls . length > 0 ) {
316- const key = `${ resolvedSymbol . moduleName } ?${ resolvedSymbol . packagePath } #${ resolvedSymbol . name } ` ;
317-
318- // Check if this is a self-reference: the type reference is within its own definition
319- const isSelfRef = typeNode . getAncestors ( ) . some ( ancestor => ancestor === decls [ 0 ] ) ;
320-
321- if ( ! visited . has ( key ) && ! isSelfRef ) {
322- visited . add ( key ) ;
323- dependencies . push ( {
324- ModPath : resolvedSymbol . moduleName || moduleName ,
325- PkgPath : this . getPkgPath ( resolvedSymbol . packagePath || packagePath ) ,
326- Name : resolvedSymbol . name ,
327- File : resolvedSymbol . filePath ,
328- Line : resolvedSymbol . line ,
329- StartOffset : resolvedSymbol . startOffset ,
330- EndOffset : resolvedSymbol . endOffset
331- } ) ;
332+ // Skip if this is a type parameter
333+ if ( typeParamNames && typeParamNames . has ( resolvedSymbol . name ) ) {
334+ // Skip this type parameter
335+ } else {
336+ const decls = resolvedRealSymbol ?. getDeclarations ( ) || [ ] ;
337+ if ( decls . length > 0 ) {
338+ const key = `${ resolvedSymbol . moduleName } ?${ resolvedSymbol . packagePath } #${ resolvedSymbol . name } ` ;
339+
340+ // Check if this is a self-reference: the type reference is within its own definition
341+ const isSelfRef = typeNode . getAncestors ( ) . some ( ancestor => ancestor === decls [ 0 ] ) ;
342+
343+ if ( ! visited . has ( key ) && ! isSelfRef ) {
344+ visited . add ( key ) ;
345+ dependencies . push ( {
346+ ModPath : resolvedSymbol . moduleName || moduleName ,
347+ PkgPath : this . getPkgPath ( resolvedSymbol . packagePath || packagePath ) ,
348+ Name : resolvedSymbol . name ,
349+ File : resolvedSymbol . filePath ,
350+ Line : resolvedSymbol . line ,
351+ StartOffset : resolvedSymbol . startOffset ,
352+ EndOffset : resolvedSymbol . endOffset
353+ } ) ;
354+ }
332355 }
333356 }
334357 }
@@ -363,6 +386,11 @@ export class TypeParser {
363386 continue ;
364387 }
365388
389+ // Skip if this is a type parameter
390+ if ( typeParamNames && typeParamNames . has ( resolvedSymbol . name ) ) {
391+ continue ;
392+ }
393+
366394 const key = `${ resolvedSymbol . moduleName } ?${ resolvedSymbol . packagePath } #${ resolvedSymbol . name } ` ;
367395 if ( visited . has ( key ) ) {
368396 continue ;
@@ -424,6 +452,12 @@ export class TypeParser {
424452 const endOffset = classExpr . getEnd ( ) ;
425453 const content = classExpr . getFullText ( ) ;
426454
455+ // Collect type parameter names
456+ const typeParamNames = new Set < string > ( ) ;
457+ for ( const typeParam of classExpr . getTypeParameters ( ) ) {
458+ typeParamNames . add ( typeParam . getName ( ) ) ;
459+ }
460+
427461 // Parse methods
428462 // eslint-disable-next-line @typescript-eslint/no-explicit-any
429463 const methods : Record < string , any > = { } ;
@@ -447,7 +481,7 @@ export class TypeParser {
447481 const typeNodes = clause . getTypeNodes ( ) ;
448482
449483 for ( const typeNode of typeNodes ) {
450- const dependencies = this . extractTypeDependencies ( typeNode , moduleName , packagePath ) ;
484+ const dependencies = this . extractTypeDependencies ( typeNode , moduleName , packagePath , typeParamNames ) ;
451485
452486 if ( clauseType === SyntaxKind . ImplementsKeyword ) {
453487 implementsInterfaces . push ( ...dependencies ) ;
0 commit comments