-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update pathCache in NodePath#_replaceWith
#12391
Conversation
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/33175/ |
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 307b003:
|
@@ -50,7 +50,7 @@ export function replaceWithMultiple(nodes: Array<Object>) { | |||
nodes = this._verifyNodeList(nodes); | |||
t.inheritLeadingComments(nodes[0], this.node); | |||
t.inheritTrailingComments(nodes[nodes.length - 1], this.node); | |||
pathCache.get(this.parent).delete(this.node); | |||
pathCache.get(this.parent)?.delete(this.node); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fix is inspired from ancestry commit that in some user cases the pathCache
is nullish in NodePath#_replaceWith
.
@@ -51,6 +51,14 @@ describe("conversion", function () { | |||
expect(generateCode(rootPath)).toBe("() => {\n return false;\n};"); | |||
}); | |||
|
|||
it("preserves arrow function body's context", function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need another test, or is this enough? (Since there is the to-do item in the PR description)
I can work on it if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is copied from the replaceWith
test above, see also #12391 (comment). The second commit fixes another regression introduced in #12302 that is not yet reported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can work on it if needed.
Appreciated. Feel free to push 😄. I am still trying to figure out how we should test the pathCache
behaviour in @babel/traverse
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm cannot find a test case that is failing before this PR but working after 😅 In the worst case, we already have the optional chaining one which should prevent regressions.
However, I found another test case that fails. It's not related to this PR, but part of the bigger `path.context` management problem:
const out = babel.transformSync("[b]", {
configFile: false,
plugins: [
() => ({
visitor: {
ExpressionStatement(path) {
path.traverse({ Identifier(p) {}, noScope: true });
const arr = path.get("expression");
const x = arr.unshiftContainer("elements", [
{ type: "Identifier", name: "x" },
])[0];
console.log("Has scope?", !!x.scope);
},
},
}),
],
});
if you comment out the path.traverse
call, this logs true
. With the path.traverse
, it logs false
.
Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fix looks good. I tried creating a test again but it's super hard, and imho it shouldn't block this PR (since it already has "indirect" tests anyway).
@@ -112,6 +112,33 @@ describe("path/replacement", function () { | |||
}); | |||
expect(visitCounter).toBe(1); | |||
}); | |||
|
|||
// https://github.com/babel/babel/issues/12386 | |||
it("updates pathCache with the replaced node", () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I come up with a slightly simplified test from the regression example: 8d8782a#diff-f6b6fd6b98ff2127cf882c020e42e695555b277d7073252187299fb7c3f875a2
This test does not depend on the behaviour of proposal-optional-chaining
and transform-typescript
.
}); | ||
expect(generate(ast).code).toMatchInlineSnapshot(` | ||
"() => { | ||
return a.b.c; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As expected v7.12.7
returns
() => {
return (a.b).c;
};
here, which means the test captures the behaviour difference from the path cache.
* add tests on regression 12386 * fix: update cache on _replaceWith * fix: pathCache in replaceWithMultiple could be nullish * Update packages/babel-traverse/src/path/replacement.js Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com> * test: add replaceWith test to traverse Co-authored-by: Brian Ng <bng412@gmail.com> Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
This PR fixes a regression introduced in #12302, where we replaced the
pathCache
toNode
-indexed Map. Before that PR, thepathCache
is searched by comparingNodePath.node === targetNode
, wheretargetNode
is defined bycontainer[key]
. After we replaced it withNode
-indexed map, whenever we assign new value tothis.container[this.key]
, i.e. inreplaceWithMultiple
, we should also update thepathCache
otherwise if we query the replaced node inpathCache
, we lost the access of previously cached NodePath. Why? Because when we updatethis.node
andthis.container[this.key]
, we only update the values of the map-backedpathCache
, which is analogous to the exact array-backedpathCache
before #12302. Now that we replacedpathCache
to a Map, we should also update the keys so that the replaced node points to the hosting NodePath.Note that the second commit of #12302 3a365bf is exactly for such purpose, to remove
this.node
from the cache since we assignnull
tothis.container[this.key]
. Since we assignreplacement
tothis.container[this.key]
inNodePath#_replaceWith
we should apply similar routine here. So we set a new cache forreplacement
and removed the old node cache entries.As a summary, the side-effect introduced in #12302 is: whenever we update the targetNode (
this.container[this.key]
) of a created NodePath, we should also update thepathCache
. I searchedthis.container[this.key] =
usage in the codebase, it seems that there are only two of them so this fix seems to be complete.Todo:
@babel/traverse
. (I will be appreciated if you come up with such test and push to this branch, so we can merge 😄)