编写 ESLint 规则,如何通过其标识符查找导出的 class?

Writing an ESLint rule, how to find an exported class, by its identifier?

我正在为插件编写 ESLint 规则。我有以下测试代码:

const test = require('./test');

module.exports.foo = class Foo {}

module.exports.test = class Test {}

我有以下规则:

module.exports = {
  create: (context) => ({
    CallExpression: (node) => {
      // The callee must be `require`.
      if (node.callee.name !== 'require') {
        return;
      }

      // Must be part of a VariableDeclarator.
      if (node.parent.type !== 'VariableDeclarator') {
        return;
      }

      const variable = node.parent.id;

      if (variable.type !== 'Identifier') {
        return;
      }

      // Now that we have the variable part of the expression `const name =
      // require('name');`, find any identifiers in the code where the
      // uppercased version of the `variable` is used.
    }
  })
}

如您所见,在 CallExpression 中,我找到 require('./test'); 以获取 test 变量名。然后我想做的,如上面代码中最后的注释所示,是找到名为 Test 的 class。我不知道该怎么做。我尝试了以下方法,但它不起作用:

const scope = context.getScope();

const capitalizedName = variable.name.charAt(0).toUpperCase() + variable.name.slice(1);

// `undefined` is returned. Why? Shouldn't it find the `Test` class, even if it's exported?
const classVariable = scope.variables.find(variable => variable.name === capitalizedName)

if (!classVariable) {
  return;
}

const foundClassVariable = classVariable.references.find(({ identifier }) =>
  ['ClassDeclaration', 'ClassExpression'].includes(identifier.parent.type),
);

但它适用于以下测试代码(当 class 未导出时):

const test = require('./test');

class Test {}

有人知道我怎样才能让它工作吗?问题是否可能出在我正在使用的范围上?如果是,我如何获取在文档根目录下定义的所有标识符,以搜索所有这些标识符?

那里有一个class表达式Test只是可以在[=中使用的class的名称21=] 来引用它,它不像 class 声明 那样关联到变量。所以换句话说:没有简单的方法可以得到 class,你必须手动搜索 AST 的所有节点并找到一个 class 表达式 名称为 Test.

  create: (context) => {
    // initialize local variables, e.g. the class names to look for

    return {
      CallExpression: (node) => {
        // register class names
      },
      ClassDeclaration(node) {
        // check class declaration
       },
      ClassExpression(node) {
         // check class expression
      },
   };
 },

这就是我最终所做的事情:

const scope = context.getScope();

const capitalizedName = variable.name.charAt(0).toUpperCase() + variable.name.slice(1);

const hasFoundClassVariable = scope.childScopes.some(childScope => childScope.type === 'class' && childScope.variables[0].name === capitalizedName)

正如您想象的那样,guide here 确实有所帮助,因为它是官方文档。