上文已经有介绍了如何根据业务需要自定义自己的规则,如果忘记了可以点击文末的链接。这一篇讲下如何实现auto fix,也就是自动修复的功能。
自定义的eslint规则,如果没有自动修复的功能,它就是不完美的规则。如何去设计auto fix需要根据各自的业务类型去分析,但是最终的原则是不变的,就是ast(抽象语法树),无论什么规则,最终都是要在这里去分析源码,再利用eslint提供的fix函数,进行修复。
定义auto fix
官网描述
如果你向 ESLint 库提交了一个 核心规则,你 必须遵循下面的约定。 具体的可以看连接:eslint.bootcss.com/docs/develo…
"use strict"
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow unnecessary semicolons",
category: "Possible Errors",
recommended: true,
url: "https://eslint.org/docs/rules/no-extra-semi"
},
fixable: "code", // 这个参数后续会分析到
schema: [] // no options
},
create: function(context) {
return {
// callback functions
};
}
};
分析auto fix
如果需要插件自动auto fix,就需要了解几个概念,什么是context, 其上面有什么属性方法等。 fix和fixable的关联。
context
context上面暴露了很多方法,具体可以看下官网链接。
在上一个分享中使用context.report(descriptor)来报告问题的代码, 也就是eslint规则的检查部分,其参数descriptor如下
context.report({
node: node,
message: "Unexpected identifier" // 代码不符合改规则时的提示
});
fix方法和元数据属性fixable
在插件中如果要支持auto fix的话,必须有这两个要素:第一:meta中的fixable属性,第二: context.report()传入对象的fix函数
fixable(元数据属性)
针对这个参数,在官网中提到,必须按照下面的规范去定义值。
fixable: "code", // 这个参数后续会分析到
从eslint源码分析fixable的参数:
源码位置: linter.js runRules函数
//在这段代码就可以看出fixable是干嘛用的,一个开关,true(支持修复) / false(不支持修复)
if (problem.fix && rule.meta && !rule.meta.fixable) {
throw new Error("Fixable rules should export a `meta.fixable` property.");
}
lintingProblems.push(problem);
其实从源码来看的话,fixable不一定是特定的值,只要有值,就会进行fix的修复
个人对于这个参数的看法: 可能是因为为了好理解,类似于语义化,文档规范了某些特定的值,能够表达具体的含义。如:‘code'是对code进行修复,'whiteSpace'是对空白字符进行修复等。
fix函数
fix函数是context.report()传入描述参数上的一个属性,用户如果需要fix,就提供这个函数。这个函数的关键是其传出来的参数。
context.report({
message: "xxx",
node,
fix(fixer) {
// TODO
}
})
参数fixer上面挂载了很多的方法,替换节点信息,获取tonken等等。可以参考官网:https://eslint.bootcss.com/docs/developer-guide/working-with-rules#applying-fixes
在fix中分析ast,获取对应的信息
到这一步,auto fix已经完成了一大半,接下来就是看如何去分析ast,如果获取到你想要的东西。
聊到ast,科班的同学们应该不陌生,抽象语法树在底层编程是很常见的,比如编译器,webpack的compiler, bable内部都是用ast去分析代码,有感兴趣的人可以自行去了解他们的异同。
分析ast
create(context) {
const sourceCode = context.getSourceCode()
return {
CallExpression(node) {
// 拦截函数调用的ast节点
const code = sourceCode.getText(node) //获取原始diamante
}
}
经过上面的代码,是不是有人疑惑这是什么东西,这就涉及到ast的遍历了。CallExpression是一个ast节点中的type,也就是类型,当遍历该ast时,如果用户有传对应的节点类型函数,内部就会去执行对应的函数,为用户提供接口去访问对应的资源。
类似于CallExpression的节点类型还有很多,比如表达式是MemberExpression等等,如果感兴趣,可以自行去了解更多关于这方面的知识。
总结
通过上面的内容,大概已经了解了一个插件如何进行auto fix, 也待大家看了下eslint一小部分源码,针对于源码如果有兴趣可以再自己去拓展开,针对写插件或者了解整个eslint都有很大的帮助。
针对上面的分享,整理和码字不容易,如果喜欢的小伙伴可以点个👍 哈。