AST

AST抽象语法树是通过树状结构展示代码的一种数据结构。

下面是js查看代码ast的网站:

https://astexplorer.net/

以下是js转换成ast以后得相关结构:

现在我们假设有下面这个场景:

在开发过程中,开发人员难免会出现在代码中忘记删除console.log()的情况,为了解决这个问题我们需要将代码中多余的console.log输出删除。

思路:

将代码转换成ast然后通过对ast树的逐层遍历查找是否存在console.log,如果存在则删除该节点,最后再讲ast转换成代码。

步骤:

1.初始化项目

npm init

 2.安装依赖

pnpm i -d @babel/parse @babel/traverse @babel/generator

3.创建src路径,然后在src路径下先创建三个文件分别是index.js  math.js test.js

4.package.json中添加脚本启动命令:

  "scripts": {
    "serve": "node ./src/index.js",
    "math": "node ./src/test.js --trace-warnings",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

5.添加math.js 和 test.js内容(这里模拟开发过程中的封装的类以及业务代码)

//math.js 添加 +-方法并且导出
const addFun = function(a, b) {
    return a + b
}

const subFun = function(a, b) {
    return a - b
}

module.exports = {
    addFun,
    subFun
}
//引入 +-法并使用 如果想测试接口  使用命令npm run math,相关命令已经在package中添加
const math = require('./math.js')
const result = math.addFun(1, 2);
const result1 = math.subFun(5, 3);

console.log('计算结果输出', result, result1);

6.添加index.js(index.js中将会把代码转换成ast然后在ast中删除console.log)

const fs = require('fs');  //node 中读写文件
const parse = require('@babel/parser'); //babel解析代码转换成ast
const traverse = require('@babel/traverse').default; //babel中进行遍历的库
const generate = require('@babel/generator').default; //babel中将ast转换成代码的库

const fileData = fs.readFileSync('./src/test.js', 'utf-8');

//获取转换成ast以后得数据
const astData = parse.parse(fileData, {
    sourceType: 'module'
})

// 输出转换成ast的数据,方便查看
// fs.writeFileSync('astData.json', JSON.stringify(astData))

traverse(astData, {
    CallExpression(path) {
        if (path.get('callee').isMemberExpression()) {
            const object = path.get('callee.object');
            const property = path.get('callee.property');

            if (object.isIdentifier({ name: 'console' }) && property.isIdentifier({ name: 'log' })) {
                path.parentPath.remove(); // 删除整个调用的父节点(表达式语句)
            }
        }
    },
    VariableDeclaration(path) {
        if (path.node.kind === 'const') {
            path.traverse({
                Identifier(innerPath) {
                    const binding = innerPath.scope.getBinding(innerPath.node.name);
                    if (binding && binding.kind === 'const' && binding.path.isVariableDeclarator()) {
                        // 给变量名称添加前缀
                        innerPath.node.name = 'zxf_' + innerPath.node.name;
                    }
                }
            })
        }
       
    },
})

const { code } = generate(astData);

fs.writeFileSync('codeNew.js', code);

7.生成的新的代码结果

const zxf_math = require('./math.js');
const zxf_result = zxf_math.addFun(1, 2);
const zxf_result1 = zxf_math.subFun(5, 3);

后续测试代码会上传外网代码库。

posted on 2024-11-27 17:00  张小饭啊  阅读(115)  评论(0)    收藏  举报