diff --git a/packages/babel-traverse/src/scope/index.ts b/packages/babel-traverse/src/scope/index.ts index a4872f2dda20..9baaec406c5a 100644 --- a/packages/babel-traverse/src/scope/index.ts +++ b/packages/babel-traverse/src/scope/index.ts @@ -1125,9 +1125,14 @@ export default class Scope { // That is, if a scope path is pattern, its parent must be Function/CatchClause // Spec 9.2.10.28: The closure created by this expression should not have visibility of - // declarations in the function body. If the binding is not a `param`-kind, + // declarations in the function body. If the binding is not a `param`-kind (as function parameters) + // or `local`-kind (as id in function expression), // then it must be defined inside the function body, thus it should be skipped - if (previousPath?.isPattern() && binding.kind !== "param") { + if ( + previousPath?.isPattern() && + binding.kind !== "param" && + binding.kind !== "local" + ) { // do nothing } else { return binding; diff --git a/packages/babel-traverse/test/scope.js b/packages/babel-traverse/test/scope.js index fbe1e1586272..5a8ea46d84d4 100644 --- a/packages/babel-traverse/test/scope.js +++ b/packages/babel-traverse/test/scope.js @@ -432,17 +432,54 @@ describe("scope", () => { ).toBe("_foo3"); }); - it("reference paths", function () { - const path = getIdentifierPath("function square(n) { return n * n}"); - const referencePaths = path.context.scope.bindings.n.referencePaths; - expect(referencePaths).toHaveLength(2); - expect(referencePaths[0].node.loc.start).toEqual({ - line: 1, - column: 28, - }); - expect(referencePaths[1].node.loc.start).toEqual({ - line: 1, - column: 32, + describe("reference paths", () => { + it("param referenced in function body", function () { + const path = getIdentifierPath("function square(n) { return n * n}"); + const referencePaths = path.context.scope.bindings.n.referencePaths; + expect(referencePaths).toHaveLength(2); + expect(referencePaths[0].node.loc.start).toEqual({ + line: 1, + column: 28, + }); + expect(referencePaths[1].node.loc.start).toEqual({ + line: 1, + column: 32, + }); + }); + it("id referenced in function body", () => { + const path = getIdentifierPath("(function n(m) { return n })"); + const { referencePaths, identifier } = path.scope.getOwnBinding("n"); + expect(identifier.start).toMatchInlineSnapshot(`10`); + expect(referencePaths).toHaveLength(1); + expect(referencePaths[0].node.start).toMatchInlineSnapshot(`24`); + }); + it("id referenced in param initializer - function expression", () => { + const path = getIdentifierPath("(function n(m = n) {})"); + const { referencePaths, identifier } = path.scope.getOwnBinding("n"); + expect(identifier.start).toMatchInlineSnapshot(`10`); + expect(referencePaths).toHaveLength(1); + expect(referencePaths[0].node.start).toMatchInlineSnapshot(`16`); + }); + it("id referenced in param initializer - function declaration", () => { + const path = getIdentifierPath("function n(m = n) {}"); + const { referencePaths, identifier } = path.scope.getBinding("n"); + expect(identifier.start).toMatchInlineSnapshot(`9`); + expect(referencePaths).toHaveLength(1); + expect(referencePaths[0].node.start).toMatchInlineSnapshot(`15`); + }); + it("param referenced in function body with id collision", () => { + const path = getIdentifierPath("(function n(n) { return n })"); + const { referencePaths, identifier } = path.scope.getOwnBinding("n"); + expect(identifier.start).toMatchInlineSnapshot(`12`); + expect(referencePaths).toHaveLength(1); + expect(referencePaths[0].node.start).toMatchInlineSnapshot(`24`); + }); + it("param referenced in param initializer with id collision", () => { + const path = getIdentifierPath("(function n(n, m = n) {})"); + const { referencePaths, identifier } = path.scope.getOwnBinding("n"); + expect(identifier.start).toMatchInlineSnapshot(`12`); + expect(referencePaths).toHaveLength(1); + expect(referencePaths[0].node.start).toMatchInlineSnapshot(`19`); }); });