Skip to content

Commit bd5abd5

Browse files
authored
fix: avoid popContext on unvisited node paths (#16305)
1 parent 3a12e20 commit bd5abd5

File tree

4 files changed

+55
-4
lines changed

4 files changed

+55
-4
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
async () => do {
2+
await 0
3+
while (0) {}
4+
0
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
async () => await async function () {
2+
await 0;
3+
while (0) {}
4+
return 0;
5+
}();

packages/babel-traverse/src/context.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,12 @@ export default class TraversalContext<S = unknown> {
118118

119119
const visited = new WeakSet();
120120
let stop = false;
121+
let visitIndex = 0;
121122

122123
// visit the queue
123-
for (const path of queue) {
124+
for (; visitIndex < queue.length; ) {
125+
const path = queue[visitIndex];
126+
visitIndex++;
124127
path.resync();
125128

126129
if (
@@ -154,9 +157,9 @@ export default class TraversalContext<S = unknown> {
154157
}
155158
}
156159

157-
// clear queue
158-
for (const path of queue) {
159-
path.popContext();
160+
// pop contexts
161+
for (let i = 0; i < visitIndex; i++) {
162+
queue[i].popContext();
160163
}
161164

162165
// clear queue

packages/babel-traverse/test/traverse.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,44 @@ describe("traverse", function () {
314314
["EXIT", "./Bar"],
315315
]);
316316
});
317+
it("should preserve the context for those nodes that are not visited in sub-traversal", () => {
318+
const code = `{ var first; function second() {} }`;
319+
const ast = parse(code);
320+
let contextLevel;
321+
traverse(
322+
ast,
323+
{
324+
enter(path) {
325+
if (path.isFunctionDeclaration()) {
326+
path.parentPath.traverse(
327+
{
328+
enter(path) {
329+
if (path.isFunctionDeclaration()) {
330+
path.parentPath.traverse(
331+
{
332+
enter(path) {
333+
if (path.isVariableDeclaration()) path.stop();
334+
},
335+
},
336+
{ level: 3 },
337+
);
338+
// the function declaration path should have state.level as 2
339+
// as it is defined within level 2 traversal and the node is
340+
// not visited in the next sub-traversal
341+
contextLevel = path.state.level;
342+
}
343+
},
344+
},
345+
{ level: 2 },
346+
);
347+
}
348+
},
349+
},
350+
undefined,
351+
{ level: 1 },
352+
);
353+
expect(contextLevel).toBe(2);
354+
});
317355
});
318356
describe("path.stop()", () => {
319357
it("should stop the traversal when a grand child is stopped", () => {

0 commit comments

Comments
 (0)