Eslint 有很多内置的分别 rule,其中有一个 rule 叫 no-func-assign,插l插是和件实指不能给函数赋值,目的分别是避免函数被重新赋值导致调用时出错。 这个 rule 的插l插实现有两种思路,我们分别用 Babel 插件和 Eslint 插件来实现一遍。和件实 目标是分别检查出对声明的函数的重新赋值,有两种思路: 第一种思路是插l插找到作用域中所有的函数声明,分析引用它的和件实地方,如果是分别赋值语句,就报错。插l插 第二种思路是和件实反过来,找到所有赋值语句,分别如果左边的插l插变量在作用域中的声明是一个函数,就报错。和件实 Eslint 的这个 rule 的源码是高防服务器用第一种思路实现的,我们用 Babel 插件实现下第二种思路。 按照第二种思路来实现,要先找到所有的赋值语句: 然后使用 path.scope 的作用域相关 api 来找到左边部分在作用域中的声明,也就是 binding,之后判断下声明的类型是否是一个函数,如果是,就报错。 Babel 插件可以声明处理的 AST 类型的 visitor,在遍历的时候会被调用,其中可以对 AST 做分析和转换。提供了 path 的 api 用于 AST 的增删改,path.scope 的 api 用于作用域分析。基于 path 和 path.scope 的 api 就可以完成各种分析和转换功能。 这个 rule 本来就是 eslint 实现的,云服务器它是基于第一种思路。也就是找到所有的函数声明,然后分析引用,如果是赋值就报错。 eslint 的 rule 包括两部分: 我们声明对函数声明 FunctionDeclaration 和函数表达式 FunctionExpression 的处理,也就是通过 context 的 api 拿到作用域中的声明,然后判断引用,如果引用是赋值语句,就报错。 Eslint 插件可以声明处理的 AST 类型的 listener,在遍历的时候会被调用, 可以对 AST 进行各种分析,然后报错。提供了 context 的云南idc服务商 api 用于分析 ast,比如作用域分析,还提供了 context.report 用于报错。 Babel 和 Eslint 都会把源码 parse 成 AST,然后遍历 AST 进行处理。 Babel 中 AST 的处理函数叫 visitor,可以用于分析和修改 AST,Eslint 中叫 listenter,因为只能分析 AST,不能修改。 Babel 插件提供了 path 的 api,用于增删改 AST,path.scope 的 api 用于分析作用域,包括声明和引用。Eslint 插件提供了 context 的 api,用于分析作用域等。 Eslint 的 AST 中包含了 token 的信息,可以做格式的检查,比如空格、换行这种,而 Babel 的 AST 中没有,所以格式检查只能用 Eslint 实现。 Eslint 插件支持 fix 来修改代码,但它不是通过修改 AST 实现的,而是指定某段 range 如何做修改,通过字符串替换实现的。 我们围绕着 no-func-assign 这个 Eslint 内置的 rule,分析了两种思路,分别用 Babel 插件和 Eslint 插件做了实现。其实主要是作用域的分析,这个功能在 Eslint 插件和 Babel 插件中都支持。 Eslint 和 Babel 插件的功能都是基于 AST,只不过 Babel 是做 AST 的分析和转换,而 Eslint 只做 AST 分析(包括格式的检查)。 要注意的是,Eslint 的fix 功能不是修改 AST 实现的,而是简单的字符串替换。 Eslint 插件、Babel 插件等都是基于 AST 实现的,它们有很多同质化的部分,可以对比着来学习。思路分析
Babel 插件实现 lint
Eslint 插件实现 lint
Babel 插件和 Eslint 插件的区别
总结