const fs = require('fs');
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let a = t.identifier('a')
let b = t.identifier('b')
let binExpr2 = t.binaryExpression('+', a, b);
let binExpr3 = t.binaryExpression('*', a, b);
let retSta2 = t.returnStatement(t.binaryExpression('+', binExpr2, t.numericLiteral(100)));
let retSta3 = t.returnStatement(t.binaryExpression('*', binExpr3, t.numericLiteral(2)));
let blockSta2 = t.blockStatement([retSta2]);
let blockSta3 = t.blockStatement([retSta3]);
let funcExpr2 = t.functionExpression(null, [a,b], blockSta2);
let funcExpr3 = t.functionExpression(null, [a,b], blockSta3);
let objProp1 = t.objectProperty(t.identifier('name'), t.stringLiteral('test'));
let objProp2 = t.objectProperty(t.identifier('add'), funcExpr2);
let objProp3 = t.objectProperty(t.identifier('mul'), funcExpr3);
let objExpr = t.objectExpression([objProp1, objProp2, objProp3])
let varDec = t.variableDeclarator(t.identifier('obj'), objExpr);
let newNode = t.variableDeclaration('let', [varDec])
let code = generator(newNode).code
fs.writeFileSync('./localNewSrc.js', code, err => {})
生成的代码:
let obj = {
name: "test",
add: function (a, b) {
return a + b + 100;
},
mul: function (a, b) {
return a * b * 2;
}
};
const visitor = {
FunctionExpression(path) {
console.log(generator(path.node).code);
}
};
// function (x, b) {
// return x + b + 10;
// }
// function (x, b) {
// return x + b * 2;
// }
const visitor = {
ReturnStatement(path) {
path.parentPath.unshiftContainer('body', [
t.expressionStatement(t.stringLiteral('Before1')),
t.expressionStatement(t.stringLiteral('Before2'))
]);
path.parentPath.pushContainer('body', t.expressionStatement(t.stringLiteral('after')));
}
};
let obj = {
name: 'test',
add: function (x, b) {
"Before1";
"Before2";
return x + b + 10;
"after";
},
mul: function (x, b) {
"Before1";
"Before2";
return x + b * 2;
"after";
}
};
unshiftContainer往容器最前面加入节点
pushContainer往容器最后面加入节点
0x05 scope
scope可以方便地查找标识符的作用域,获取并修改标识符的所有引用,以及判断标识符是否为参数或常量
以下面的代码为例
const a = 1000;
let b = 2000;
let obj = {
name: 'test',
add: function(a) {
a = 400;
b = 300;
let e = 700;
function demo() {
let d = 600;
}
demo();
return a + a + b + 100 + obj.name;
}
};
obj.add(100);
获取标识符作用域
const visitor = {
Identifier(path) {
if (path.node.name == 'e') {
console.log(generator(path.scope.block).code);
}
}
};
// function (a) {
// a = 400;
// b = 300;
// let e = 700;
// function demo() {
// let d = 600;
// }
// demo();
// return a + a + b + 100 + obj.name;
// }
scope.block属性来获取标识符作用域,返回Node对象
上述代码中变量e是定义在add函数内部的,作用域范围为整个add
若遍历的是一个函数,需要去获取父级作用域
const visitor = {
FunctionDeclaration(path) {
console.log(generator(path.scope.block).code);
}
};
// function demo() {
// let d = 600;
// }
const visitor = {
FunctionDeclaration(path) {
console.log(generator(path.scope.parent.block).code);
}
};
// function (a) {
// a = 400;
// b = 300;
// let e = 700;
// function demo() {
// let d = 600;
// }
// demo();
// return a + a + b + 100 + obj.name;
// }
标识符绑定
scope.getBinding('a')
const visitor = {
FunctionDeclaration(path) {
let bindingA = path.scope.getBinding("a");
let bindingDemo = path.scope.getBinding("demo");
console.log(bindingA);
console.log(bindingA.referenced); // true
console.log(bindingA.references); // 2
console.log(generator(bindingA.scope.block).code);
console.log(generator(bindingDemo.scope.block).code);
}
};
// 打印了两次
function (a) {
a = 400;
b = 300;
let e = 700;
function demo() {
let d = 600;
}
demo();
return a + a + b + 100 + obj.name;
}
const a = 1000;
let b = 2000;
let obj = {
name: 'test',
add: function (a) {
a = 666;
b = 300;
let e = 700;
function demo() {
let d = 600;
}
demo();
return a + a + b + 100 + obj.name;
}
};
obj.add(100);
const _0x2ba6ea = 1000;
let _0x2ba6ea15 = 2000;
let _0x2ba6ea18 = {
name: 'test',
add: function (_0x2ba6ea14) {
_0x2ba6ea14 = 400;
_0x2ba6ea15 = 300;
let _0x2ba6ea9 = 700;
function _0x2ba6ea12() {
let _0x2ba6ea11 = 600;
}
_0x2ba6ea12();
return _0x2ba6ea14 + _0x2ba6ea14 + _0x2ba6ea15 + 100 + _0x2ba6ea18.name;
}
};
_0x2ba6ea18.add(100);
让我们多定义一些函数,并让其局部变量重名
const a = 1000;
let b = 2000;
let obj = {
name: 'test',
add: function(a) {
a = 400;
b = 300;
let e = 700;
function demo() {
let a = 600;
}
function demo2() {
let a = 500;
}
demo();
return a + a + b + 100 + obj.name;
}
};
obj.add(100);
const _0x2ba6ea = 1000;
let _0x2ba6ea17 = 2000;
let _0x2ba6ea20 = {
name: 'test',
add: function (_0x2ba6ea16) {
_0x2ba6ea16 = 400;
_0x2ba6ea17 = 300;
let _0x2ba6ea9 = 700;
function _0x2ba6ea14() {
let _0x2ba6ea11 = 600;
}
function _0x2ba6ea12() {
let _0x2ba6ea13 = 500;
}
_0x2ba6ea14();
return _0x2ba6ea16 + _0x2ba6ea16 + _0x2ba6ea17 + 100 + _0x2ba6ea20.name;
}
};
_0x2ba6ea20.add(100);