英文:
find return statements in function body with typescript compiler api
问题
我想在方法体中使用 TypeScript 编译器 API 查找返回语句。
我的函数体是未知的,所以我希望不必静态访问不同的节点。我发现有一个名为 visitFunctionBody
的函数,但它需要一个上下文。我看到的示例似乎是从转换器工厂获取上下文的,但 TypeScript 不再导出这样的成员,而且我甚至不确定这是否符合我的需求。
那么如何在函数体中查找返回语句?
我尝试了以下方法:
function findReturnStatements() {
const children: Node[] = [];
node.forEachChild((childNode) => {
children.push(childNode);
});
return node.filter(isReturnStatement);
}
但这可能会根据函数体的形状而失败。
someMethod() {
return 3;
}
// 与
someMethod() {
try {
return 3;
} catch (e) {
return 4;
}
}
英文:
Followup of https://stackoverflow.com/questions/76505561/find-node-of-specific-syntaxkind-in-asl-tree but focused on return statements for future googlers.
I would like to find return statements in a method body with the typescript compiler api.
My function body is unknown, so I hope to not have to access the different nodes statically. I found there is a function visitFunctionBody
but that requires a context. The example I've seen seem to get a context from a transformer factory but typescript does not export such a member anymore and I'm not even sure this does what I need to do.
So how can one find return statements in a body ?
I've tried something along the lines of:
function findReturnStatements() {
const children: Node[] = [];
node.forEachChild((childNode) => {
children.push(childNode);
});
return node.filter(isReturnStatement);
}
But this can fail depending on the shape of the body
someMethod() {
return 3;
}
// vs
someMethod() {
try {
return 3;
} catch (e) {
return 4;
}
}
答案1
得分: 1
你可能想要类似这样的内容:
// 未经测试,很可能存在错误,但这应该是一个很好的起点
function* getReturnStmts(node: ts.Node): Iterable<ts.ReturnStatement | ts.Expression> {
if (ts.isReturnStatement(node)) {
yield node;
} else if (ts.isBlock(node) || ts.isCaseClause(node) || ts.isDefaultClause(node)) {
for (const stmt of node.statements) {
yield* getReturnStmts(stmt);
}
} else if (ts.isIfStatement(node)) {
yield* getReturnStmts(node.thenStatement);
if (node.elseStatement) {
yield* getReturnStmts(node.elseStatement);
}
} else if (ts.isIterationStatement(node, true)) {
yield* getReturnStmts(node.statement);
} else if (ts.isSwitchStatement(node)) {
for (const clause of node.caseBlock.clauses) {
yield* getReturnStmts(clause);
}
} else if (ts.isTryStatement(node)) {
yield* getReturnStmts(node.tryBlock);
if (node.catchClause) {
yield* getReturnStmts(node.catchClause.block);
}
if (node.finallyBlock) {
yield* getReturnStmts(node.finallyBlock);
}
} else if (
ts.isMethodDeclaration(node) || ts.isFunctionDeclaration(node) ||
ts.isArrowFunction(node) || ts.isFunctionExpression(node) ||
ts.isConstructorDeclaration(node)
) {
if (node.body != null) {
if (ts.isBlock(node.body)) {
yield* getReturnStmts(node.body);
} else {
yield node.body;
}
}
}
}
请注意,箭头函数可以具有简洁的主体,仅为一个表达式(例如 () => 1
),因此它除了返回 ts.ReturnStatement
外还返回 ts.Expression
。
英文:
You probably want something like this:
// untested and very likely has a bug, but it should be a good starting point
function* getReturnStmts(node: ts.Node): Iterable<ts.ReturnStatement | ts.Expression> {
if (ts.isReturnStatement(node)) {
yield node;
} else if (ts.isBlock(node) || ts.isCaseClause(node) || ts.isDefaultClause(node)) {
for (const stmt of node.statements) {
yield* getReturnStmts(stmt);
}
} else if (ts.isIfStatement(node)) {
yield* getReturnStmts(node.thenStatement);
if (node.elseStatement) {
yield* getReturnStmts(node.elseStatement);
}
} else if (ts.isIterationStatement(node, true)) {
yield* getReturnStmts(node.statement);
} else if (ts.isSwitchStatement(node)) {
for (const clause of node.caseBlock.clauses) {
yield* getReturnStmts(clause);
}
} else if (ts.isTryStatement(node)) {
yield* getReturnStmts(node.tryBlock);
if (node.catchClause) {
yield* getReturnStmts(node.catchClause.block);
}
if (node.finallyBlock) {
yield* getReturnStmts(node.finallyBlock);
}
} else if (
ts.isMethodDeclaration(node) || ts.isFunctionDeclaration(node) ||
ts.isArrowFunction(node) || ts.isFunctionExpression(node) ||
ts.isConstructorDeclaration(node)
) {
if (node.body != null) {
if (ts.isBlock(node.body)) {
yield* getReturnStmts(node.body);
} else {
yield node.body;
}
}
}
}
Note that arrow functions can have a consise body, which is just an expression (ex. () => 1
), so that's why it returns ts.Expression
in addition to ts.ReturnStatement
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论