现在写 JavaScript 项目,ESlint 可以说是标配。静态检查虽不执行代码,主要检查 AST 和文件路径,但也可以检查出很多东西。比如说 import 的文件是否真是存在,React Hooks 用法有没有问题等等。有时候一些项目写法上有特殊的限制,也可以通过 eslint 来自动化代码检查。这时就需要自定义 eslint rules。
自定义 rules
rules 的写法详细的可以看ESLint 文档,不再赘述。
最重要的地方就是 export 的对象的 create 对象。在 create 对象中,key 是一个selector,value 则是对应的 handler,在 handler 就可以通过context.report
来对有问题的代码报错。语法树可以用AST Explorer来看。
例子:小程序自定义组件中防止额外触发内置事件
在小程序自定义组件可以通过this.triggerEvent('eventName', ...)
来触发eventName
事件。但是有一些内置事件是不需要额外触发的,比如tap
, longpress
之类的。我们就而可以写一个 rule 来禁止手动触发这些事件。
根据AST,可以写出下面这个 rule。
// 内置事件
const bulidinEvents = [
'tap',
'longpress',
'longtap',
// ...
];
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'disallow trigger builtin events manually in miniprogram',
category: 'Possible Errors',
recommended: true,
},
schema: [
{
enum: ['always', 'never'],
},
],
},
create: function (context) {
return {
CallExpression: function (node) {
const { callee, arguments: args } = node;
if (callee.type === 'MemberExpression') {
const { object, property } = callee;
if (object.type === 'ThisExpression') {
if (
property.type === 'Identifier' &&
property.name === 'triggerEvent'
) {
if (args.length > 0) {
const firstArgrament = args[0];
const eventName = firstArgrament.value;
if (bulidinEvents.includes(eventName)) {
context.report({
node,
message: `trigger builtin events manually in miniprogram is forbidden`,
});
}
}
}
}
}
},
};
},
};
rulesdir
要让 rule 生效最简单的方式就是使用runtime rule 的机制,但是不是任何时候我们都有机会去加--rules
。例如在一些集成度比较高的框架中比如 CRA 之类,只提供了修改 config 的方式,不支持修改命令行参数。
如果为了项目特异的规则专门发一个 plugin 的 npm 包,不仅显得有些小题大做,还不好维护。最好还是能把 rules 放在主项目内。
这里我们可以用eslint-plugin-rulesdir,它利用了 eslint plugin 的机制,在 rules getter 中获取某个目录内的所有 JS 文件作为 rules, 这样们就能在 rules 配置中通过rulesdir/<fileanme>
来使用自定义的 rules 了。
比如将上面我们写的 rule 命名为no-trigger-builtin-events-manually.js
,放到对应目录中,就而可以配置
'rulesdir/no-trigger-builtin-events-manually': ['error', 'always']
来禁用多余的手动事件触发。