5、插入函数调用参数(实战)

148 阅读1分钟

目的

只是学习概念,还不够需要实战敲一下 才靠谱

实战需求

image.png

思路分析

image.png

image.png

代码实现

image.png

image.png

image.png

const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const types = require("@babel/types");
const generate = require("@babel/generator").default;

const sourceCode = `
    console.log(123);

    function func() {
        console.info(234);
    }

    export default class Test {
        say() {
            console.debug(345);
        }
        render() {
            return <div>{console.error(456)}</div>
        }
    }
`;

const ast = parser.parse(sourceCode, {
  sourceType: "unambiguous",
  plugins: ["jsx"],
});

traverse(ast, {
  CallExpression(path, state) {
    if (
      types.isMemberExpression(path.node.callee) &&
      path.node.callee.object.name === "console" &&
      ["log", "info", "error", "debug"].includes(path.node.callee.property.name)
    ) {
      const { line, column } = path.node.loc.start;
      path.node.arguments.unshift(
        types.stringLiteral(`filename: (${line}, ${column})`)
      );
    }
  },
});

const { code, map } = generate(ast);
console.log(code);

结果展示

image.png

image.png

简化判断条件

image.png

image.png

改个需求试试?

这个事情 工作遇到就很烦,但 这里不是工作 哈哈

image.png

分析

image.png

代码实现

image.png

改成插件试试

image.png

代码实现

const targetCalleeName = ['log', 'info', 'error', 'debug'].map(item => `console.${item}`);

module.exports = function({types, template}) {
    return {
        visitor: {
            CallExpression(path, state) {
                if (path.node.isNew) {
                    return;
                }
  
                const calleeName = generate(path.node.callee).code;

                 if (targetCalleeName.includes(calleeName)) {
                    const { line, column } = path.node.loc.start;
                    
                    const newNode = template.expression(`console.log("${state.filename || 'unkown filename'}: (${line}, ${column})")`)();
                    newNode.isNew = true;

                    if (path.findParent(path => path.isJSXElement())) {
                        path.replaceWith(types.arrayExpression([newNode, path.node]))
                        path.skip();
                    } else {
                        path.insertBefore(newNode);
                    }
                }
            }
        }
    }
}

通过 @babel/core 的 transformSync 方法来编译代码,并引入上面的插件:

const { transformFileSync } = require('@babel/core');
const insertParametersPlugin = require('./plugin/parameters-insert-plugin');
const path = require('path');

const { code } = transformFileSync(path.join(__dirname, './sourceCode.js'), {
    plugins: [insertParametersPlugin],
    parserOpts: {
        sourceType: 'unambiguous',
        plugins: ['jsx']       
    }
});

console.log(code);

把前面调用 parse、traverse、generate 的代码改造成了 babel 插件的形式,只需要提供一个转换函数,traverse 的过程中会自动调用。

可以试试, 运行 babel 环境可以使用这个 codesandbox.io/p/sandbox/y…