Skip to content

Figure out an approach to NodePath 'hub' object tracking with better cache behavior #6437

@loganfsmyth

Description

@loganfsmyth

I recently realized we've got bug with our invalidation logic for NodePath that can cause some real weirdness. Here it is on ASTExplorer and here:

var mem = template("property.access")();

traverse(mem, {noScope: true});

var p2 = path.insertAfter(mem)[0];

console.log(p2.get("expression").hub);

will print undefined for hub even through p2.hub is the Hub class instance.

Which is surprising because in

if (!hub && parentPath) {
, the hub value is explicitly supposed to pass down.

It fails in this case because on

if (pathCheck.node === targetNode) {
if a value is found in the cache, we never bother bailing out.

The problem is, what do we do. Two options come to mind:

  1. Overwrite the .hub on the cache result.
  2. Only accept items from the cache if the hub is correct.

Option 1

Pretty gross because we could just as easily be introducing another bug by removing a Hub instance that was supposed to be there

Option 2

Sounds reasonable, until you realize that we actually crucially rely on this gross caching behavior to instantiate NodePath with the correct Hub instance in the first place.

In File init in

we create the root NodePath, but then we never really do anything with it. Traversal begins on
traverse(file.ast, visitor, file.scope);
, which never explicitly mentions this.path at all. That path ends up being used, thus using the root Hub, because it is present in the cache. If we explicitly test for the Hub in the cache, we'll break this weird cache-based pass-through logic.

Solution?

To me, the "feature" we're breaking in option 2 is totally a mistake to rely on since it is essentially relying on sideeffects to the extreme. This means we need a way to do two things:

  1. Initialize the NodePath up front, so it can be stored on the File class instance
  2. Perform a traversal using this NodePath, while ensuring that same traversal logic we have now is preserved.

The exact details on how we do those two things is up in the air, but feels like something we should figure out ASAP.

Incidentally, this same bug is the reason we have to do

traverse.clearNode(node);
to explicitly clear the cache, otherwise every node we get pack from babel-template would trigger this bug, due to the internal traversal, which doesn't have a hub, polluting the cache.

Metadata

Metadata

Labels

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

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions