From 95b29d50038957473c40287f7de4f501e7ecc52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Mon, 26 Feb 2024 16:01:11 -0500 Subject: [PATCH 1/2] fix: avoid popContext on unvisited node paths --- .../fixtures/do-expressions/regression-16293/input.js | 5 +++++ .../do-expressions/regression-16293/output.js | 5 +++++ packages/babel-traverse/src/context.ts | 11 +++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 packages/babel-plugin-proposal-do-expressions/test/fixtures/do-expressions/regression-16293/input.js create mode 100644 packages/babel-plugin-proposal-do-expressions/test/fixtures/do-expressions/regression-16293/output.js diff --git a/packages/babel-plugin-proposal-do-expressions/test/fixtures/do-expressions/regression-16293/input.js b/packages/babel-plugin-proposal-do-expressions/test/fixtures/do-expressions/regression-16293/input.js new file mode 100644 index 000000000000..b3abe5f3bba8 --- /dev/null +++ b/packages/babel-plugin-proposal-do-expressions/test/fixtures/do-expressions/regression-16293/input.js @@ -0,0 +1,5 @@ +async () => do { + await 0 + while (0) {} + 0 +} diff --git a/packages/babel-plugin-proposal-do-expressions/test/fixtures/do-expressions/regression-16293/output.js b/packages/babel-plugin-proposal-do-expressions/test/fixtures/do-expressions/regression-16293/output.js new file mode 100644 index 000000000000..cd904d3f903d --- /dev/null +++ b/packages/babel-plugin-proposal-do-expressions/test/fixtures/do-expressions/regression-16293/output.js @@ -0,0 +1,5 @@ +async () => await async function () { + await 0; + while (0) {} + return 0; +}(); diff --git a/packages/babel-traverse/src/context.ts b/packages/babel-traverse/src/context.ts index cd4f1ca8c694..c63bd6031a4b 100644 --- a/packages/babel-traverse/src/context.ts +++ b/packages/babel-traverse/src/context.ts @@ -118,9 +118,12 @@ export default class TraversalContext { const visited = new WeakSet(); let stop = false; + let visitIndex = 0; // visit the queue - for (const path of queue) { + for (; visitIndex < queue.length; ) { + const path = queue[visitIndex]; + visitIndex++; path.resync(); if ( @@ -154,9 +157,9 @@ export default class TraversalContext { } } - // clear queue - for (const path of queue) { - path.popContext(); + // pop contexts + for (let i = 0; i < visitIndex; i++) { + queue[i].popContext(); } // clear queue From 67dd9d660212e26886e3732e9a9f9efd3f483656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Tue, 27 Feb 2024 21:03:35 -0500 Subject: [PATCH 2/2] add traverser behaviour test case --- packages/babel-traverse/test/traverse.js | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/packages/babel-traverse/test/traverse.js b/packages/babel-traverse/test/traverse.js index 2de1bb68b3f8..aa11e00b6d6d 100644 --- a/packages/babel-traverse/test/traverse.js +++ b/packages/babel-traverse/test/traverse.js @@ -314,6 +314,44 @@ describe("traverse", function () { ["EXIT", "./Bar"], ]); }); + it("should preserve the context for those nodes that are not visited in sub-traversal", () => { + const code = `{ var first; function second() {} }`; + const ast = parse(code); + let contextLevel; + traverse( + ast, + { + enter(path) { + if (path.isFunctionDeclaration()) { + path.parentPath.traverse( + { + enter(path) { + if (path.isFunctionDeclaration()) { + path.parentPath.traverse( + { + enter(path) { + if (path.isVariableDeclaration()) path.stop(); + }, + }, + { level: 3 }, + ); + // the function declaration path should have state.level as 2 + // as it is defined within level 2 traversal and the node is + // not visited in the next sub-traversal + contextLevel = path.state.level; + } + }, + }, + { level: 2 }, + ); + } + }, + }, + undefined, + { level: 1 }, + ); + expect(contextLevel).toBe(2); + }); }); describe("path.stop()", () => { it("should stop the traversal when a grand child is stopped", () => {