在 TypeScript 编译器 API 中查找函数体中的返回语句。

huangapple go评论57阅读模式
英文:

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&lt;ts.ReturnStatement | ts.Expression&gt; {
  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. () =&gt; 1), so that's why it returns ts.Expression in addition to ts.ReturnStatement.

huangapple
  • 本文由 发表于 2023年6月19日 18:41:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76505841.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定