背景
AST 是非常有用的
。
今天下午听了小组一个老哥做的AST分享,深以为然。
为了加深印象,就写了篇总结,顺便分享给大家,希望能给朋友们一些启发。
AST有用,口说无凭, 且看几个具体的案例
。
且不说:
Vue => React
React => Vue
的代码转换方法,
我们就看一个可以无痛升级旧版React
的工具:
react-codemod
代码地址:https://github.com/reactjs/re...
这个工具,功能十分强大,使用起来也很方便,只需要运行一行命令:
npx react-codemod <transform> <path> [...options]
这些无不借助了AST。
下面我们就进入今天的内容。
正文
本文的主要内容包括:
- 1 理论: AST 概念
- 2 实践: 使用 AST 实现一个代码转换工具, 把
var
转换成let
- 3 实践: 使用 AST 实现一个Eslint 插件, 禁用 console
- 4 实践: 使用 AST 实现一个Babel插件, 过滤 Debugger
1. AST 基本概念
AST 是什么
AST is a hierarchical program representation that presents source code structure according to the grammar of a programming language, each AST node corresponds to an item of a source code.
在计算机科学中,抽象语法
和抽象语法树
其实是源代码的抽象语法结构的树状表现形式
。
常用的浏览器就是通过将js代码转化为抽象语法树来进行下一步的分析等其他操作。
所以将js转化为抽象语法树更利于程序的分析。
AST 能做什么
- 代码语法的检查
- 代码风格的检查
- 代码的格式化
- 代码的高亮
- 代码错误提示
- 代码自动补全
- 等等。
AST 三板斧
- 生成AST
- 遍历和更新AST
- 将AST重新生成源码
为了便于理解, 我们看一个具体的例子。
这里顺便给大家介绍一个十分有用的网站: https://astexplorer.net/
你譬如:
声明, 变量, 类型等各种信息一应俱全。
而且这里也提供了各种插件模版供你选择:
十分的方便。
我们就根据这个例子, 我们做个小的实践。
2. 实践: 使用AST实现一个代码转换工具, 把var转换成let
比如, 现在要重构一个老项目, 你要把项目里的var 全部替换成let, 你会怎么做?
手动替换?
或者借助工具一键替换?
现在就教你一招:一键替换大法
。
首先还是要介绍一把大杀器: jscodeshift
jscodeshift 是一个 Javscript Codemod 工具,官方对 Codemod 的解释是:
Codemod is a tool/library to assist you with large-scale codebase refactors that can be partially automated but still require human oversight and occasional intervention.
jscodeshift 也是基于 esprima
的,其通过 path 可以很容易的在 AST 上遍历 node
。
现在我们就开始替换项目中的var.
首先,到 https://astexplorer.net 里面编写代码.
模板我们选: jscodeshift
官方自带的例子, 把变量名字反转:
我们现在要改变量, 这个工具很贴心的一点是可以高亮实时对照,
现在, 找到kind === var
的对象, 替换成let
:
得到如下代码:
export default function transformer(file, api) {
const j = api.jscodeshift;
return j(file.source)
.find(j.VariableDeclaration, { kind: 'var'})
.forEach(path => {
const letStatement = j.variableDeclaration('let', path.node.declarations)
j(path).replaceWith(letStatement)
})
.toSource();
}
这样也可以:
path.node.kind = 'let'; // 传入的实际是一个引用
实际效果:
大功告成!
假如我项目里有几个文件也需要相同的操作:
简单安装:
sudo npm install -g jscodeshift
执行:
jscodeshift -t transform.js ./src/demo.js --dry --print
这里用了--dry 和 --print
--dry
加上之后,不会立刻把新生成的代码覆盖源文件
--print
是打印出来看看
在实际项目里, 你需要在独立的分支里
操作,新生成代码之后, 需要你再检查检查
, review没有问题
之后才能合并。
3. 使用AST实现一个Eslint 插件, 禁用console
和上面的类似, 我们也可以做一个eslint 插件, 功能也很简单: 检查到使用console的时候就报错
。
期望达到的效果:
// Do not use console methods (at 1:9)
console.log('haha')
// --------^
我们这次选择 babel-eslint
模版。
代码实现:
const disallowMethods = ["log", "info", "warn", "error", "dir"];
export default function(context) {
return {
Identifier(node) {
const isConsoleMethod =
disallowMethods.includes(node.name) &&
node.parent.type === "MemberExpression" &&
node.parent.object.name === "console";
if (!isConsoleMethod) return;
context.report({
node,
message: "Do not use console methods"
});
}
};
}
实际效果:
简单有效。
不过你要是非要玩什么骚操作,比如自定义一个log, 那就没得搞了。
最后, 你可以把这段代码封装成一个完整的插件:
你可以自行实践。
4. 使用AST实现一个Babel插件, 过滤debugger
最后一个是过滤源代码中的debugger, Transform 我们选择babelv7
这个插件,我们期望达到的效果是:
var a = 1
debugger
function test() {
debugger
a++
}
debugger
到:
var a = 1;
function test() {
a++;
}
这也是一个十分有用的功能。
代码实现:
export default function (babel) {
const {
types: t
} = babel;
return {
name: "ast-transform", // not required
visitor: {
DebuggerStatement(path) {
path.remove()
}
}
};
}
实际效果:
总结
内容大概就是这么多,没什么难度,重在讲述理论和入门
。
对AST还不熟练的同学, 希望这篇可以帮助到你。
后面还有会AST在我们实际项目中的应用
, 我也会写一个实战篇
, 敬请期待!
以上。
延伸阅读
https://www.toptal.com/javasc...
关注我
如果你觉得这篇内容对你挺有启发,那就关注我吧~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。