原理
@babel/parser
解析代码生成ast语法树@babel/traverse
遍历并修改语法树@babel/types
提供各种node节点构造器,方便构造ast语法树节点@babel/generator
将ast语法树生成代码字符串
源码文件
加入我们有个源码文件code.js
文件
js
const user = {
name: '张三',
// 性别
gender: '男',
}
export {user}
构建脚本
从code.js
中读取源码,通过babel
的各个工具库对源码进行解析、遍历修改,给user
对象增加age
属性,值为18
,并且添加行注释。
js
const fs = require('fs');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generator = require('@babel/generator').default;
const t = require('@babel/types');
// 转换逻辑
const transform = ()=>{
// 读取源码
const sourceCode = fs.readFileSync('./code.js', 'utf-8');
// 1. 解析代码
const ast = parser.parse(sourceCode,{
sourceType: 'module'
})
// 2. 遍历语法树
traverse(ast, {
// 遍历 VariableDeclarator 类型节点
VariableDeclarator(path){
const {node} = path;
// 判断是user节点
if(node.id.name === 'user'){
// 构造一个 age:18 的属性节点
const newNode = t.objectProperty(t.identifier('age'), t.numericLiteral(18));
// 添加行注释
t.addComment(newNode, 'leading', '年龄', true);
// 将新构造的属性节点push到user对象节点中
node.init.properties.push(newNode);
}
}
})
// 3. 生成代码
const {code} = generator(ast);
// 将代码字符串写入new-code.js文件
fs.writeFileSync('./new-code.js', code)
}
// 执行代码
transform();
其它用法
path.traverse(options)
: 遍历path的子节点
path.skip()
: 跳过遍历当前路径的子路径
path.stop()
: 完全停止遍历
js
traverse(ast, {
// 遍历 VariableDeclarator 类型节点
VariableDeclarator(path){
const {node} = path;
// 判断是user节点
if(node.id.name === 'user'){
// 构造一个 age:18 的属性节点
const newNode = t.objectProperty(t.identifier('age'), t.numericLiteral(18));
// 添加行注释
t.addComment(newNode, 'leading', '年龄', true);
// 将新构造的属性节点push到user对象节点中
node.init.properties.push(newNode);
// 遍历user的子节点
path.traverse({
Function(innerPath) {
innerPath.skip(); // 跳过遍历当前路径的子路径
},
ReferencedIdentifier(innerPath, state) {
state.iife = true;
innerPath.stop(); // 完全停止遍历
}
})
}
}
})