前端工具-定制ESLint 插件以及了解ESLint的运行原理 (2)

在深度遍历的过程中,生效的每条规则都会对其中的某一个或多个选择器进行监听,每当匹配到选择器,监听该选择器的rule,都会触发对应的回调。

4. 具体的检测规则等细节内容。 开发规则 规则默认模板

打开rule生成的模板文件lib/rules/settimeout-no-number.js, 清理一下文件,删掉不必要的选项:

module.exports = { meta: { docs: { description: "setTimeout 第二个参数禁止是数字", }, fixable: null, // 修复函数 }, // rule 核心 create: function(context) { // 公共变量和函数应该在此定义 return { // 返回事件钩子 }; } };

删掉的配置项,有些是ESLint官方核心规则才是用到的配置项,有些是暂时不必了解的配置,需要用到的时候,可以自行查阅ESLint 文档

create方法-监听选择器

上文ESLint原理第三部中提到的:在深度遍历的过程中,生效的每条规则都会对其中的某一个或多个选择器进行监听,每当匹配到选择器,监听该选择器的rule,都会触发对应的回调。

create返回一个对象,对象的属性设为选择器,ESLint会收集这些选择器,在AST遍历过程中会执行所有监听该选择器的回调。

// rule 核心 create: function(context) { // 公共变量和函数应该在此定义 return { // 返回事件钩子 Identifier: (node) => { // node是选中的内容,是我们监听的部分, 它的值参考AST } }; } 观察AST:

创建一个ESLint rule需要观察代码解析成AST,选中你要检测的代码,然后进行一些判断。

以下代码都是通过astexplorer.net在线解析的。

setTimeout(()=>{ console.log('settimeout') }, 1000)

setTimeout第二个参数为数字时的AST

rule完整文件

lib/rules/settimeout-no-number.js:

module.exports = { meta: { docs: { description: "setTimeout 第二个参数禁止是数字", }, fixable: null, // 修复函数 }, // rule 核心 create: function (context) { // 公共变量和函数应该在此定义 return { // 返回事件钩子 'CallExpression': (node) => { if (node.callee.name !== 'setTimeout') return // 不是定时器即过滤 const timeNode = node.arguments && node.arguments[1] // 获取第二个参数 if (!timeNode) return // 没有第二个参数 // 检测报错第二个参数是数字 报错 if (timeNode.type === 'Literal' && typeof timeNode.value === 'number') { context.report({ node, message: 'setTimeout第二个参数禁止是数字' }) } } }; } };

context.report():这个方法是用来通知ESLint这段代码是警告或错误的,用法如上。在查看context和context.report()的文档。

规则写完了,原理就是依据AST解析的结果,做针对性的检测,过滤出我们要选中的代码,然后对代码的值进行逻辑判断

可能现在会有点懵逼,但是不要紧,我们来写一下测试用例,然后用debugger来看一下代码是怎么运行的。

测试用例:

测试文件tests/lib/rules/settimeout-no-number.js:

/** * @fileoverview setTimeout 第二个参数禁止是数字 * @author OBKoro1 */ "use strict"; var rule = require("../../../lib/rules/settimeout-no-number"), // 引入rule RuleTester = require("eslint").RuleTester; var ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 7, // 默认支持语法为es5 }, }); // 运行测试用例 ruleTester.run("settimeout-no-number", rule, { // 正确的测试用例 valid: [ { code: 'let someNumber = 1000; setTimeout(()=>{ console.log(11) },someNumber)' }, { code: 'setTimeout(()=>{ console.log(11) },someNumber)' } ], // 错误的测试用例 invalid: [ { code: 'setTimeout(()=>{ console.log(11) },1000)', errors: [{ message: "setTimeout第二个参数禁止是数字", // 与rule抛出的错误保持一致 type: "CallExpression" // rule监听的对应钩子 }] } ] });

下面来学习一下怎么在VSCode中调试node文件,用于观察rule是怎么运行的。

实际上打console的形式,也是可以的,但是在调试的时候打console实在是有点慢,对于node这种节点来说,信息也不全,所以我还是比较推荐通过debugger的方式来调试rule。

在VSCode中调试node文件

点击下图中的设置按钮, 将会打开一个文件launch.json

在文件中填入如下内容,用于调试node文件。

在rule文件中打debugger或者在代码行数那里点一下小红点。

点击图中的开始按钮,进入debugger

vscode 设置

{ // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "启动程序", // 调试界面的名称 // 运行项目下的这个文件: "program": "${workspaceFolder}/tests/lib/rules/settimeout-no-number.js", "args": [] // node 文件的参数 }, // 下面是用于调试package.json的命令 之前可以用,貌似vscode出了点bug导致现在用不了了 { "name": "Launch via NPM", "type": "node", "request": "launch", "runtimeExecutable": "npm", "runtimeArgs": [ "run-script", "dev" //这里的dev就对应package.json中的scripts中的dev ], "port": 9229 //这个端口是调试的端口,不是项目启动的端口 }, ] } 运行测试用例进入断点

在lib/rules/settimeout-no-number.js中打一些debugger

点击开始按钮,以调试的形式运行测试文件tests/lib/rules/settimeout-no-number.js

开始调试rule。

发布插件

eslint插件都是以npm包的形式来引用的,所以需要把插件发布一下:

注册:如果你还未注册npm账号的话,需要去注册一下。

登录npm: npm login

发布npm包: npm publish即可,ESLint已经把package.json弄好了。

集成到项目:

安装npm包:npm i eslint-plugin-korolint -D

常规的方法: 引入插件一条条写入规则

// .eslintrc.js module.exports = { plugins: [ 'korolint' ], rules: { "korolint/settimeout-no-number": "error" } }

extends继承插件配置:

当规则比较多的时候,用户一条条去写,未免也太麻烦了,所以ESLint可以:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspdgy.html