编写 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 确实有所帮助,因为它是官方文档。
我正在为插件编写 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 确实有所帮助,因为它是官方文档。