使用@babel/core 实现一个简单代码转换功能

709 阅读1分钟
  • @babel/core Babel 的编译器,核心 API 都在这里面,比如常见的 transform、parse
  • @babel/types 用于 AST 节点的 Lodash 式工具库, 它包含了构造、验证以及变换 AST 节点的方法,对编写处理 AST 逻辑非常有用
  • AST explorer 在线查看ast语法树结构

语法树分析

//转换前
import { flatten, get } from "lodash"; 
//转换后
import flatten from "lodash/flatten";
import get from "lodash/get";

对比两个语法树,由一个body由一个ImportDeclaration 变成了两个 ImportDeclaration;
specifiers 由ImportSpecifier 变成了ImportDefaultSpecifier

转换前语法树:转换前 转换后语法树:

代码实现

	const babel = require("@babel/core");
    const t = require("babel-types");

    const code = `import { flatten, get } from "lodash";`;

    const importPlugin = {
      visitor: {
        ImportDeclaration(path, state) { //path是路径,state 表示状态、里面又一个opts代表参数对象{library: "lodash"}
          let node = path.node; //获得节点 ImportDeclaration
          let source = node.source; // ImportDeclaration.source
          let specifiers = node.specifiers; // ImportDeclaration.specifiers
          if (
            state.opts.library === source.value &&
            !t.isImportDefaultSpecifier(specifiers[0]) //判断当前的source是否跟目标的library一致,且第一个不是转换后的默认导入
          ) {
          // 生成新的[importDeclaration, importDeclaration]新节点
            let newSources = specifiers.map((item) => {
              let defaultSpecifer = t.importDefaultSpecifier(item.local);//生成importDefaultSpecifier 默认导入
              return t.importDeclaration(
                [defaultSpecifer],
                t.stringLiteral(`${source.value}/${item.local.name}`)
              ); 
            });
            path.replaceWithMultiple(newSources); //替换
          }
        },
      },
    };

    const result = babel.transform(code, {
      plugins: [[importPlugin, { library: "lodash" }]],
    });
    //import flatten from "lodash/flatten";
    //import get from "lodash/get";
    console.log(result.code);