快来享受 AST 转换的乐趣
有用的链接
var 替换成 let
假设有如下源代码:
js
var foo = 234;我们想将它转换为如下的代码:
js
let foo = 234;对比转换前后的两张 ast 的截图:


发现只有 kind 的值从 "var" 变成了 "let"。
所以我们只需遍历 ast,当遇到 VariableDeclaration 时,替换 king 的值就可以了。
js
const parser = require("@babel/parser")
const traverse = require("@babel/traverse")
const generate = require("@babel/generator")
const code = `
var foo = 234;
`
const ast = parser.parse(code)
traverse.default(ast, {
VariableDeclaration(path) {
if (path.node.kind === 'var') {
path.node.kind = 'let'
}
}
})
const outputCode = generate.default(ast)
console.log(outputCode.code)
根据情况,将 var 替换成 let 或 const
js
const parser = require("@babel/parser")
const traverse = require("@babel/traverse")
const generate = require("@babel/generator")
const code = `
var foo = 234;
var bar = 123;
foo = 250;
console.log(foo, bar);
`
const ast = parser.parse(code)
// 先找到所有赋值语句
// 把所有将会被重新赋值的变量存到一个数组中
// 这些变量在声明时需要使用关键字 let
const letSet = new Set()
traverse.default(ast, {
AssignmentExpression(path) {
letSet.add(path.node.left.name)
}
})
traverse.default(ast, {
VariableDeclaration(path) {
const Identifier = path.node.declarations[0].id.name
if (letSet.has(Identifier)) {
path.node.kind = 'let'
} else {
path.node.kind = 'const'
}
}
})
const outputCode = generate.default(ast)
console.log(outputCode.code)
箭头函数转换
js
const parser = require("@babel/parser")
const traverse = require("@babel/traverse")
const generate = require("@babel/generator")
const t = require("@babel/types")
const code = `
const sum = (a, b) => a + b;
`
const ast = parser.parse(code)
traverse.default(ast, {
ArrowFunctionExpression(path) {
const funcExpress = t.functionExpression(
null, // Identifier 函数变量名
path.node.params,
t.blockStatement([
t.returnStatement(path.node.body)
])
)
path.replaceWith(funcExpress)
}
})
const outputCode = generate.default(ast)
console.log(outputCode.code)
tree-shaking
js
const parser = require("@babel/parser")
const traverse = require("@babel/traverse")
const generate = require("@babel/generator")
const code = `
const add = (a, b) => a + b;
function subtract(a, b) { return a - b }
const num1 = 1;
const num2 = 10;
const num3 = 100;
// 表达式 1
add(num1, num2);
// 表示式 2
num2 + num3
`
const ast = parser.parse(code)
// 首先找出表示式中用到的所有变量
const usedId = new Set()
traverse.default(ast, {
ExpressionStatement(path) {
path.traverse({
Identifier(path) {
usedId.add(path.node.name)
}
})
}
})
traverse.default(ast, {
VariableDeclaration(path) {
for(let declaration of path.node.declarations) {
if (!usedId.has(declaration.id.name)) {
path.remove()
}
}
},
FunctionDeclaration(path) {
if (!usedId.has(path.node.id.name)) {
path.remove()
}
},
})
const outputCode = generate.default(ast)
console.log(outputCode.code)
babel-import-plugin
js
const parser = require("@babel/parser")
const traverse = require("@babel/traverse")
const generate = require("@babel/generator")
const t = require("@babel/types")
const code = `
import { flatten } from 'lodash'
flatten([1, [2, [3, [4]], 5]])
`
const ast = parser.parse(code, {
sourceType: "module"
})
traverse.default(ast, {
ImportDeclaration(path){
if (t.isImportSpecifier(path.node.specifiers[0])) {
const importName = path.node.specifiers[0].local.name
const sourceName = path.node.source.value
const declation = t.importDeclaration(
[t.importDefaultSpecifier(t.identifier(importName))],
t.stringLiteral(`${sourceName}/${importName}`)
)
path.replaceWith(declation)
}
}
})
const outputCode = generate.default(ast)
console.log(outputCode.code)