Javascript-Babel-AST-traverse-NodePath.evaluate方法增强

本文最后更新于:2020年12月30日 上午

信息

NodePath.evaluate()方法非常的好用,但本身也存在着一些限制
进行一些源码修改能提升它的能力

处理更多全局函数

NodePath.evaluate() 方法不支持对parseInt等全局函数的处理
我们可以通过修改源码,让其支持

  1. 打开方法定义文件,查看函数处理定义
    文件路径:node_modules\@babel\traverse\lib\path\evaluation.js
  2. 在文件中找到会处理的全局函数定义
    在代码中找到定义位置
    1
    2
    const VALID_CALLEES = ["String", "Number", "Math"];
    const INVALID_METHODS = ["random"];
    定义包含两种:
  • VALID_CALLEES 会进行处理的全局函数

  • INVALID_METHODS 只要包含就不会处理的全局函数

    根据你的需要对定义进行修改即可

例:希望支持处理 parseInt 函数

在会进行处理的定义里添加函数名即可

1
const VALID_CALLEES = ["String", "Number", "Math""parseInt"];

"string"["length"]引用不支持

我们知道访问object对象有两种方法,"string"["length"]"string".length

NodePath.evaluate() 只会处理 "string".length 这种方式的表达式,而 "string"["length"] 是不会直接进行处理的

你可以通过可以把 "string"["length"] 转变为 "string".length 这种形式的方式来实现适配
也可以通过修改源码达到目的

  1. 打开方法定义文件,查看函数处理定义
    文件路径:node_modules\@babel\traverse\lib\path\evaluation.js

  2. 找到 _evaluate 函数,查看 对 MemberExpression 表达式的处理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    if (path.isMemberExpression() && !path.parentPath.isCallExpression({
    callee: node
    })) {
    const property = path.get("property");
    const object = path.get("object");
    if (object.isLiteral() && property.isIdentifier()) {
    const value = object.node.value;
    const type = typeof value;
    if (type === "number" || type === "string") {
    return value[property.node.name];
    }
    }
    }

    它主要处理在第二个 if 语句里面

    1
    if (object.isLiteral() && property.isIdentifier()) {......}

    但是它只考虑了 object 是字面量且 property 必须是 Idernifier 的情况,也就是类似 "string".length的表达式

现在把另外一种情况的代码补充进去, 代码如下:

1
2
3
4
5
6
7
else if (object.isLiteral() && property.isLiteral()) {
const value = object.node.value;
const type = typeof value;
if (type === "number" || type === "string") {
return value[property.node.value];
}
}

将代码直接添加到 if 语句的后面即可

多了一种判断逻辑和对应的处理逻辑,就能处理"string"["length"]类型的代码了