-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Description
💻
- Would you like to work on a fix?
How are you using Babel?
Programmatic API (babel.transform, babel.parse)
Input code
function a(Math) {
var b = Math.ceil(580.82);
}Configuration file name
No response
Configuration
No response
Current and expected behavior
I am writing a Babel plugin and using path.evaluate() to statically evaluate expressions. I noticed that path.evaluate() fails to check for local bindings when processing CallExpression that involves a MemberExpression (e.g., Math.abs()).
If I shadow the global Math object locally, evaluate() still acts as if it is using the global Math object.
Reproduction Steps (in plugin visitor):
visitor: {
CallExpression(path) {
// When visiting `Math.abs(-1)` in the input code
const result = path.evaluate();
console.log(result);
}
}Current Behavior:
It returns { confident: true, value: 1 }. It ignores the local const Math declaration.
Expected Behavior:
It should return { confident: false } (or evaluate the local function if supported), because Math refers to the local variable, not the global built-in.
Environment
System:
OS: Windows 11 10.0.26100
Binaries:
Node: 22.18.0
Yarn: 1.22.22
npm: 10.9.3
pnpm: 10.27.0
npmPackages:
eslint: catalog: => 9.39.2
Possible solution
The issue seems to be in packages/babel-traverse/src/path/evaluation.ts.
In the _evaluate function, specifically within the if (path.isCallExpression()) block. When handling Identifier callees (like Number(1)), there is a check for !path.scope.getBinding(callee.node.name).
However, inside the if (callee.isMemberExpression()) block (which handles Math.xxx), this check is missing.
Proposed fix:
Add a binding check for the object identifier.
// packages/babel-traverse/src/path/evaluation.ts
if (callee.isMemberExpression()) {
const object = callee.get("object");
const property = callee.get("property");
if (
object.isIdentifier() &&
property.isIdentifier() &&
!path.scope.getBinding(object.node.name) && // <--- ADD THIS CHECK
isValidObjectCallee(object.node.name) &&
!isInvalidMethod(property.node.name)
) {
// ...
}
}Additional context
No response