Proposal: defer rule listener calls until after traversal is complete
See original GitHub issueFor a long time, rules have had a slight usability issue where the parent
property of a node is only present after a node is traversed and its listeners have been invoked. This can lead to confusing issues (e.g. https://github.com/eslint/eslint/issues/9101) where a function call on a node can change behavior depending on whether the node has been traversed.
Previously, there has been discussion about adding the parent
property during the scope analysis traversal (https://github.com/eslint/eslint-scope/issues/27). However, I realized there’s a much easier solution: We can just defer all rule listener calls until after traversal is complete.
The current traversal logic looks roughly like this (pseudocode):
for each node in the AST in traversal order:
node.parent = parentNode
for each rule listener that matches the node:
invoke the listener on the node
We could change it to this:
for each node in the AST in traversal order:
node.parent = parentNode
for each rule listener that matches the node:
push (listener, node) into a FIFO queue
for each (listener, node) pair in the queue:
invoke the listener on the node
The effect is that all parent
properties would be present for all rule listeners.
We would need to evaluate the performance effects of doing this. I suspect that most of the time spent traversing the AST is a result of enumerating the children of a node, so after all the nodes have already been enumerated in order, I don’t think invoking a function on a small fraction of the nodes will create a big performance problem. (Actually, this might allow us to move scope analysis into the same traversal too, since rules wouldn’t be able to observe the scope until the traversal is complete.)
Note that rules can observe the AST before traversal starts, so they would still be able to observe nodes without a (edit: actually, this can be avoided.)parent
property.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:1
- Comments:7 (7 by maintainers)
TSC Summary: This issue proposes updating traversal logic to call rule listeners after all nodes have a
parent
property. The issue was previously accepted by the TSC, but it was reverted because there was some compatibility impact (a plugin was relying on the fact that the AST is non-circular, and another plugin was relying on the parent property not existing in some cases).TSC Question: Should we schedule this as a breaking change in v5.0.0?
In today’s TSC meeting, the TSC decided to accept this as a breaking change for 5.0.