使用babel解析并修改代码

原理

  1. @babel/parser 解析代码生成ast语法树
  2. @babel/traverse 遍历并修改语法树
  3. @babel/types 提供各种node节点构造器,方便构造ast语法树节点
  4. @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(); // 完全停止遍历
            }
        })
      }
    }
  })
相关推荐
霸王蟹3 分钟前
React 19中如何向Vue那样自定义状态和方法暴露给父组件。
前端·javascript·学习·react.js·typescript
小野猫子12 分钟前
Web GIS可视化地图框架Leaflet、OpenLayers、Mapbox、Cesium、ArcGis for JavaScript
前端·webgl·可视化3d地图
shenyan~23 分钟前
关于 js:9. Node.js 后端相关
前端·javascript·node.js
uwvwko38 分钟前
ctfshow——web入门254~258
android·前端·web·ctf·反序列化
所待.3831 小时前
深入解析SpringMVC:从入门到精通
前端·spring·mvc
逃逸线LOF1 小时前
CSS之精灵图(雪碧图)Sprites、字体图标
前端·css
海天胜景2 小时前
jqGrid冻结列错行问题,将冻结表格(悬浮表格)与 正常表格进行高度同步
前端
清风细雨_林木木3 小时前
解决 Tailwind CSS 代码冗余问题
前端·css
三天不学习3 小时前
VueUse/Core:提升Vue开发效率的实用工具库
前端·javascript·vue.js·vueuse
余道各努力,千里自同风3 小时前
CSS实现文本自动平衡text-wrap: balance
前端·css