Skip to content

Regression: path.parentPath.get(path.listKey) can clobber a traversal's visitors with those from a separate traversal in the global path cache #12570

@jedwards1211

Description

@jedwards1211

Bug Report

  • I would like to work on a fix!

Input Code

const {parse} = require('@babel/core')
const generate = require('@babel/generator').default
const traverse = require('@babel/traverse').default

const code = `
import { Foo } from './Foo'
import { Bar } from './Bar'
`

const presets = [
  ['@babel/preset-env', { targets: { node: 'current' } }],
]

const ast = parse(code, {plugins, presets})

traverse(ast, {
  Program(path) {
    path.traverse({
      ImportDeclaration: {
        enter(path) {
          console.log('ENTER', generate(path.node).code)
          if (path.node.source.value === './Bar')
            path.parentPath.get(path.listKey)
        },
        exit(path) {
          console.log('EXIT ', generate(path.node).code)
        }
      }
    })
  }
})

Expected behavior

I haven't bisected to find the version that introduced the regression yet, but with @babel/core, @babel/traverse, and @babel/preset-env 7.4.5, the exit visitor is called for both import statements:

ENTER import { Foo } from './Foo';
EXIT  import { Foo } from './Foo';
ENTER import { Bar } from './Bar';
EXIT  import { Bar } from './Bar';

Current behavior

With these versions:
├─ @babel/[email protected]
├─ @babel/[email protected]
└─ @babel/[email protected]

The exit visitor for the second import statement isn't called because path.parentPath.get(path.listKey) has the side effect of replacing path.opts with those of the parent traversal (which only has a Program visitor)

ENTER import { Foo } from './Foo';
EXIT  import { Foo } from './Foo';
ENTER import { Bar } from './Bar';

(missing EXIT import { Bar } from './Bar')

Additional context

babel-plugin-flow-runtime is no longer working after I upgraded @babel/*, and I uncovered this issue debugging it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    i: regressionoutdatedA closed issue/PR that is archived due to age. Recommended to make a new issuepkg: traverse

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions