Skip to content

Commit

Permalink
refactor(tsUtils): move logic for looking up method type definition
Browse files Browse the repository at this point in the history
  • Loading branch information
jackofdiamond5 committed Jul 22, 2021
1 parent b40187a commit 016c6aa
Showing 1 changed file with 48 additions and 20 deletions.
68 changes: 48 additions & 20 deletions projects/igniteui-angular/migrations/common/tsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,24 +261,9 @@ export const getTypeDefinitionAtPosition =
return langServ.getDefinitionAndBoundSpan(entryPath, definition.textSpan.start).definitions[0];
}
if (definition.kind.toString() === 'method') {
/** TODO: use typechecker for all the things? */
const typeChecker = langServ.getProgram().getTypeChecker();
const sourceFile = langServ.getProgram().getSourceFile(definition.fileName);

const classDeclaration = sourceFile.statements
.filter((m): m is tss.ClassDeclaration => m.kind === tss.SyntaxKind.ClassDeclaration)
.find(m => m.name && m.name.getText() === definition.containerName);

const node = classDeclaration.members
.filter((m): m is tss.MethodDeclaration => m.kind === tss.SyntaxKind.MethodDeclaration)
.find(m => m.name.getText() === definition.name);

const returnType = typeChecker.getReturnTypeOfSignature(typeChecker.getSignatureFromDeclaration(node));
const name = returnType.symbol.escapedName.toString();
const fileName = returnType.symbol.declarations[0].getSourceFile().fileName;

return { name, fileName };
return getMethodTypeDefinition(langServ, definition);
}

let typeDefs = getTypeDefinitions(langServ, definition.fileName || entryPath, definition.textSpan.start);
// if there are no type definitions found, the identifier is a ts property, referred in an internal/external template
// or is a reference in a decorator
Expand All @@ -300,9 +285,11 @@ export const getTypeDefinitionAtPosition =
return null;
}

// find the class declaration in the source file where the member that we want to migrate is declared
// atm we are explicitly ignoring unnamed class declarations like - export default class { ... }
const classDeclaration = sourceFile.statements
.filter((m): m is tss.ClassDeclaration => m.kind === tss.SyntaxKind.ClassDeclaration)
.find(m => m.name && m.name.getText() === definition.containerName);
.find(m => m.name?.getText() === definition.containerName);

if (!classDeclaration) {
// there must be at least one class declaration in the .ts file and the property must belong to it
Expand Down Expand Up @@ -358,10 +345,51 @@ export const isMemberIgniteUI =
const shiftMatchPosition = (matchPosition: number, content: string): number => {
do {
matchPosition--;
} while (matchPosition > 0
&& !content[matchPosition - 1].trim()
} while (matchPosition > 0 && !content[matchPosition - 1].trim()
|| content[matchPosition - 1] === SynaxTokens.MemberAccess);
return matchPosition;
};

/**
* Looks up a method's definition return type.
*
* @param langServ The TypeScript LanguageService.
* @param definition The method definition.
*/
const getMethodTypeDefinition = (langServ: tss.LanguageService, definition: tss.DefinitionInfo):
Pick<tss.DefinitionInfo, 'name' | 'fileName'> | null => {
// TODO: use typechecker for all the things?
const sourceFile = langServ.getProgram().getSourceFile(definition.fileName);

// find the class declaration in the source file where the method that we want to migrate is declared
const classDeclaration = sourceFile.statements
.filter((m): m is tss.ClassDeclaration => m.kind === tss.SyntaxKind.ClassDeclaration)
.find(m => m.name?.getText() === definition.containerName);

// find the node in the class declaration's members which represents the method
const methodDeclaration = classDeclaration?.members
.filter((m): m is tss.MethodDeclaration => m.kind === tss.SyntaxKind.MethodDeclaration)
.find(m => m.name.getText() === definition.name);

if (!methodDeclaration) {
return null;
}

// use the TypeChecker to resolve implicit/explicit method return types
const typeChecker = langServ.getProgram().getTypeChecker();
const signature = typeChecker.getSignatureFromDeclaration(methodDeclaration);
if (!signature) {
return null;
}
const returnType = typeChecker.getReturnTypeOfSignature(signature);
const name = returnType.symbol.escapedName.toString();
if (returnType.symbol.declarations?.length > 0) {
// there should never be a case where a type is declared in more than one file
const fileName = returnType.symbol.declarations[0].getSourceFile().fileName;
return { name, fileName };
}

return null;
};

//#endregion

0 comments on commit 016c6aa

Please sign in to comment.