const parser = require("@babel/parser"); const traverse = require("@babel/traverse").default; // 将js代码转换成AST // const { parse } = require("@babel/parser"); // 用来遍历AST中的节点 // const traverse = require("@babel/traverse").default; // AST转换成js const generator = require("@babel/generator").default; // 用来判断节点类型和生成新的节点 const types = require("@babel/types"); const jscode = ` var a = 123; const b = -5; let c = window; function d(){ var f = c.btoa("hello,AST!"); return a + b + f ; } `; let ast = parser.parse(jscode); const restoreVarDeclarator = { VariableDeclarator(path) { let {id,init} = path.node; if (!types.isIdentifier(id)) return; let initPath = path.get("init"); if (initPath.isUnaryExpression({operator:"+"}) || initPath.isUnaryExpression({operator:"-"})) {// -5或者 +"3" 也可以算作是字面量 if (!types.isLiteral(init.argument)) return; } //如果初始值非Literal节点或者Identifier节点,不做还原 //有时候为MemberExpression节点时,也可以还原,视情况而论 //请大家自行添加,通用插件不做处理。 else if (!initPath.isLiteral() && !initPath.isIdentifier()) { return; } const binding = path.scope.getBinding(id.name); //判断初始值是否被更改 if (!binding || !binding.constant) return; //获取所有引用的地方并替换 let referPaths = binding.referencePaths; for (let referPath of referPaths) { referPath.replaceWith(init); } //替换完毕,直接删除即可。 path.remove(); }, } traverse(ast, restoreVarDeclarator); let { code } = generator(ast); console.log(code);