babel / babel/babel

[Bug]: Path Traversal with Removed Nodes in ConditionalExpression

Open
#15,265 5 comments 0 reactions 0 assignees View on GitHub
pkg: traverse
Dominant language
TypeScript
Stars
44k
Forks
6k
Avg merge
5d 15h
Merged PRs (30d)
23

Description

### 💻

- [ ] Would you like to work on a fix?

### How are you using Babel?

Programmatic API (`babel.transform`, `babel.parse`)

### Input code

It's a custom transform so it's hard to give an exact replication without working too hard on it, but here's the gist:

```js
console.log(a ? a() : b());
```

Where there is a custom transform plugin running over this source, which will inline the "DCE" branch if a is true to output:

```js
console.log(a());
```

Internally this is done via a check and replacement on the test node:

```js
if (t.isConditionalExpression(path.parentPath) && path.parentPath.node.consequent === path.node) {
path.stop();
path.parentPath.replaceWith(path.parentPath.get('consequent'));
}
```

In the above, it is still continuing to iterate the `b()` function. In addition, adding a `path.parentPath.get('alternate').remove()` results in the error:

```
TypeError: unknown file: Property consequent of ConditionalExpression expected node to be of a type
["Expression"] but instead got undefined
```

I understand this is a very specific iteration replacement case, but thought it worth posting anyway so at least there is some record of it.

### Configuration file name

_No response_

### Configuration

_No response_

### Current and expected behavior

It should be possible to remove a sibling Node and affect its iteration in a transform.

### Environment

7.20.5

### Possible solution

A liveness check in the iterator for replacements / removals / stop calls should properly be able to avoid iterating dead branches of the tree.

### Additional context

_No response_

Contributor guide

Open the contributing guide

Research direction

Start with Babel's traversal iterator and the replacement, removal, and stop behavior described in the issue; reproduce the case through the programmatic API using the shown ConditionalExpression transform. Done means removed or replaced sibling nodes are not visited afterward, and the traversal does not produce an invalid ConditionalExpression error.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.