浅谈ESlint原理

Lint 是基于静态代码进行的分析,对于 ESLint 来说,我们的输入的核心就是 rules 及其配置以及需要进行 Lint 分析的源码。ESLint 默认使用 espree 来解析我们的 JS 语句,来生成AST。

可以通过**AST explorer** 来查看一段代码被解析成AST之后的结构。

1
2
console.log('1')
debugger

拿到代码的AST之后,就会去遍历AST的过程中去触发各个规则检查,再根据rule的规则去判断这一段代码是否符合eslint的规范。

先看一条 no-debugger 规则的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
module.exports = {
meta: {
type: "problem",
docs: {
description: "disallow the use of `debugger`",
category: "Possible Errors",
recommended: true,
url: "https://eslint.org/docs/rules/no-debugger"
},
fixable: null,
schema: [],
messages: {
unexpected: "Unexpected 'debugger' statement."
}
},
create(context) {
return {
DebuggerStatement(node) {
context.report({
node,
messageId: "unexpected"
});
}
};
}

可以看到,一条 rule 就是一个 node 模块,主要由 metacreate 两部分组成,

  • meta 代表了这条规则的元数据,比如类别,文档,可修复选项, schema

  • create 主要表达了这条 rule 具体会怎么分析处理代码。Create 返回的是一个存储了一系列回调函数的对象,这些函数将在遍历AST的时候触发。

  • create 返回的对象 key 分三类:

    • AST 选择器,在向下遍历AST的时候触发。选择器用于匹配 AST 节点,最常见的选择器名就是AST节点类型,通过选择器,可以获取对应选中节点内容,随后就可以针对选中的内容做一定的判断;
  • AST 选择器加:exit,如:Program:exit,在遍历完节点,向上返回的时候触发;

  • 代码路径分析对应的事件名,路径分析是用来处理条件语句、循环语句中的代码,比如可以帮助我们找到不可达的代码。

上述代码中的DebuggerStatement 对应之前截图中的 AST 中的 debugger 的节点,上面的代码表示在匹配到 debugger 语句时,会抛出 “Unexpected ‘debugger’ statement.”

获得AST 和 rules 之后,接下来的工作就是遍历所有的rules添加监听事件,然后遍历整个AST去触发所有监听事件进行代码检查。

官方源码: https://github.com/eslint/eslint