Skip to content

Commit 4da40d7

Browse files
angrychowHoblovski
authored andcommitted
filtering type parameters
1 parent 7b83d39 commit 4da40d7

3 files changed

Lines changed: 83 additions & 24 deletions

File tree

ts-parser/src/parser/FunctionParser.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,12 @@ export class FunctionParser {
655655
const types: Dependency[] = [];
656656
const visited = new Set<string>();
657657

658+
// Collect all type parameter names from this node to filter them out
659+
const typeParamNames = new Set<string>();
660+
for (const typeParam of node.getTypeParameters()) {
661+
typeParamNames.add(typeParam.getName());
662+
}
663+
658664
// Extract from type references and find their definitions
659665
const typeNodes: TypeNode[] = node.getDescendantsOfKind(SyntaxKind.TypeReference)
660666

@@ -696,6 +702,10 @@ export class FunctionParser {
696702

697703
if (directSymbol) {
698704
const directTypeName = directSymbol.getName();
705+
// Skip if this is a type parameter
706+
if (typeParamNames.has(directTypeName)) {
707+
continue;
708+
}
699709
if (!this.isPrimitiveType(directTypeName)) {
700710
const [resolvedSymbol, resolvedRealSymbol] = this.symbolResolver.resolveSymbol(directSymbol, typeNode);
701711
if (resolvedSymbol && !resolvedSymbol.isExternal) {
@@ -740,6 +750,11 @@ export class FunctionParser {
740750
continue;
741751
}
742752

753+
// Skip if this is a type parameter
754+
if (typeParamNames.has(typeName)) {
755+
continue;
756+
}
757+
743758
const symbol = typeRef.getSymbol();
744759
if (!symbol) {
745760
continue;

ts-parser/src/parser/TypeParser.ts

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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);

ts-parser/test-repo/src/test-export-default.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,21 @@ export const bar = () => {
1212

1313
export type Status = 'normal' | 'abnormal'
1414

15+
export type Result<T> = T | Status
16+
1517
export type ServerStatus = {
1618
code: number;
1719
status: Status;
1820
}
1921

20-
export const flipStatus = (s: Status): Status => {
22+
export const convert = <T>(s: T): Result<T> => {
23+
// 如果输入是字符串,返回 'normal',否则返回输入本身
24+
if (typeof s === 'string') {
25+
return 'normal';
26+
}
27+
return s;
28+
};
29+
30+
export const flipStatus = (s: Status): Result<Status> => {
2131
return s === 'normal' ? 'abnormal' : 'normal';
2232
}

0 commit comments

Comments
 (0)