Fix parameter expression get binding (#10912)
* fix: parameter expression closure should not have access to the declaration inside function body * fix: renameVisitor should skip when a pattern is a scope * address review comments
This commit is contained in:
parent
ee5b79d75d
commit
fc5365fe4a
@ -64,7 +64,8 @@ export const Expression = {
|
||||
};
|
||||
|
||||
export const Scope = {
|
||||
types: ["Scopable"],
|
||||
// When pattern is inside the function params, it is a scope
|
||||
types: ["Scopable", "Pattern"],
|
||||
checkPath(path) {
|
||||
return t.isScope(path.node, path.parent);
|
||||
},
|
||||
|
||||
@ -897,10 +897,27 @@ export default class Scope {
|
||||
|
||||
getBinding(name: string) {
|
||||
let scope = this;
|
||||
let previousPath;
|
||||
|
||||
do {
|
||||
const binding = scope.getOwnBinding(name);
|
||||
if (binding) return binding;
|
||||
if (binding) {
|
||||
// Check if a pattern is a part of parameter expressions.
|
||||
// 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,
|
||||
// then it must be defined inside the function body, thus it should be skipped
|
||||
if (
|
||||
previousPath &&
|
||||
previousPath.isPattern() &&
|
||||
previousPath.parentPath.isFunction() &&
|
||||
binding.kind !== "param"
|
||||
) {
|
||||
// do nothing
|
||||
} else {
|
||||
return binding;
|
||||
}
|
||||
}
|
||||
previousPath = scope.path;
|
||||
} while ((scope = scope.parent));
|
||||
}
|
||||
|
||||
|
||||
7
packages/babel-traverse/test/fixtures/rename/parameter-default-1/input.js
vendored
Normal file
7
packages/babel-traverse/test/fixtures/rename/parameter-default-1/input.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
let a = "outside";
|
||||
|
||||
function f(g = () => a) {
|
||||
let a = "inside";
|
||||
return g();
|
||||
}
|
||||
|
||||
3
packages/babel-traverse/test/fixtures/rename/parameter-default-1/options.json
vendored
Normal file
3
packages/babel-traverse/test/fixtures/rename/parameter-default-1/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
6
packages/babel-traverse/test/fixtures/rename/parameter-default-1/output.js
vendored
Normal file
6
packages/babel-traverse/test/fixtures/rename/parameter-default-1/output.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
let a = "outside";
|
||||
|
||||
function f(g = () => a) {
|
||||
let z = "inside";
|
||||
return g();
|
||||
}
|
||||
9
packages/babel-traverse/test/fixtures/rename/parameter-default-1/plugin.js
vendored
Normal file
9
packages/babel-traverse/test/fixtures/rename/parameter-default-1/plugin.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
FunctionDeclaration(path) {
|
||||
path.scope.rename("a", "z");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
5
packages/babel-traverse/test/fixtures/rename/parameter-default-10/input.js
vendored
Normal file
5
packages/babel-traverse/test/fixtures/rename/parameter-default-10/input.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
let a = "outside";
|
||||
|
||||
function r({ a: b }, { [a]: { c } = a }) {
|
||||
g(a);
|
||||
}
|
||||
3
packages/babel-traverse/test/fixtures/rename/parameter-default-10/options.json
vendored
Normal file
3
packages/babel-traverse/test/fixtures/rename/parameter-default-10/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
11
packages/babel-traverse/test/fixtures/rename/parameter-default-10/output.js
vendored
Normal file
11
packages/babel-traverse/test/fixtures/rename/parameter-default-10/output.js
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
let z = "outside";
|
||||
|
||||
function r({
|
||||
a: b
|
||||
}, {
|
||||
[z]: {
|
||||
c
|
||||
} = z
|
||||
}) {
|
||||
g(z);
|
||||
}
|
||||
9
packages/babel-traverse/test/fixtures/rename/parameter-default-10/plugin.js
vendored
Normal file
9
packages/babel-traverse/test/fixtures/rename/parameter-default-10/plugin.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
FunctionDeclaration(path) {
|
||||
path.scope.rename("a", "z");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
5
packages/babel-traverse/test/fixtures/rename/parameter-default-2/input.js
vendored
Normal file
5
packages/babel-traverse/test/fixtures/rename/parameter-default-2/input.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
let a = "outside";
|
||||
|
||||
function h(a, g = () => a) {
|
||||
return g();
|
||||
}
|
||||
3
packages/babel-traverse/test/fixtures/rename/parameter-default-2/options.json
vendored
Normal file
3
packages/babel-traverse/test/fixtures/rename/parameter-default-2/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
5
packages/babel-traverse/test/fixtures/rename/parameter-default-2/output.js
vendored
Normal file
5
packages/babel-traverse/test/fixtures/rename/parameter-default-2/output.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
let a = "outside";
|
||||
|
||||
function h(z, g = () => z) {
|
||||
return g();
|
||||
}
|
||||
9
packages/babel-traverse/test/fixtures/rename/parameter-default-2/plugin.js
vendored
Normal file
9
packages/babel-traverse/test/fixtures/rename/parameter-default-2/plugin.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
FunctionDeclaration(path) {
|
||||
path.scope.rename("a", "z");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
6
packages/babel-traverse/test/fixtures/rename/parameter-default-3/input.js
vendored
Normal file
6
packages/babel-traverse/test/fixtures/rename/parameter-default-3/input.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
let a = "outside";
|
||||
|
||||
function j(g = a) {
|
||||
let a = "inside";
|
||||
return g;
|
||||
}
|
||||
3
packages/babel-traverse/test/fixtures/rename/parameter-default-3/options.json
vendored
Normal file
3
packages/babel-traverse/test/fixtures/rename/parameter-default-3/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
6
packages/babel-traverse/test/fixtures/rename/parameter-default-3/output.js
vendored
Normal file
6
packages/babel-traverse/test/fixtures/rename/parameter-default-3/output.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
let a = "outside";
|
||||
|
||||
function j(g = a) {
|
||||
let z = "inside";
|
||||
return g;
|
||||
}
|
||||
9
packages/babel-traverse/test/fixtures/rename/parameter-default-3/plugin.js
vendored
Normal file
9
packages/babel-traverse/test/fixtures/rename/parameter-default-3/plugin.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
FunctionDeclaration(path) {
|
||||
path.scope.rename("a", "z");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
8
packages/babel-traverse/test/fixtures/rename/parameter-default-4/input.js
vendored
Normal file
8
packages/babel-traverse/test/fixtures/rename/parameter-default-4/input.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
let a = "outside";
|
||||
|
||||
function k([{
|
||||
g = a
|
||||
}]) {
|
||||
let a = "inside";
|
||||
return g;
|
||||
}
|
||||
3
packages/babel-traverse/test/fixtures/rename/parameter-default-4/options.json
vendored
Normal file
3
packages/babel-traverse/test/fixtures/rename/parameter-default-4/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
8
packages/babel-traverse/test/fixtures/rename/parameter-default-4/output.js
vendored
Normal file
8
packages/babel-traverse/test/fixtures/rename/parameter-default-4/output.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
let a = "outside";
|
||||
|
||||
function k([{
|
||||
g = a
|
||||
}]) {
|
||||
let z = "inside";
|
||||
return g;
|
||||
}
|
||||
9
packages/babel-traverse/test/fixtures/rename/parameter-default-4/plugin.js
vendored
Normal file
9
packages/babel-traverse/test/fixtures/rename/parameter-default-4/plugin.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
FunctionDeclaration(path) {
|
||||
path.scope.rename("a", "z");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
8
packages/babel-traverse/test/fixtures/rename/parameter-default-5/input.js
vendored
Normal file
8
packages/babel-traverse/test/fixtures/rename/parameter-default-5/input.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
let a = "outside";
|
||||
|
||||
function f([{
|
||||
[a]: g
|
||||
}]) {
|
||||
let a = "inside";
|
||||
return g;
|
||||
}
|
||||
3
packages/babel-traverse/test/fixtures/rename/parameter-default-5/options.json
vendored
Normal file
3
packages/babel-traverse/test/fixtures/rename/parameter-default-5/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
8
packages/babel-traverse/test/fixtures/rename/parameter-default-5/output.js
vendored
Normal file
8
packages/babel-traverse/test/fixtures/rename/parameter-default-5/output.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
let a = "outside";
|
||||
|
||||
function f([{
|
||||
[a]: g
|
||||
}]) {
|
||||
let z = "inside";
|
||||
return g;
|
||||
}
|
||||
9
packages/babel-traverse/test/fixtures/rename/parameter-default-5/plugin.js
vendored
Normal file
9
packages/babel-traverse/test/fixtures/rename/parameter-default-5/plugin.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
FunctionDeclaration(path) {
|
||||
path.scope.rename("a", "z");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
5
packages/babel-traverse/test/fixtures/rename/parameter-default-6/input.js
vendored
Normal file
5
packages/babel-traverse/test/fixtures/rename/parameter-default-6/input.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
let a = "outside";
|
||||
|
||||
function n(g = (a = a) => {}) {
|
||||
let a = "inside";
|
||||
}
|
||||
3
packages/babel-traverse/test/fixtures/rename/parameter-default-6/options.json
vendored
Normal file
3
packages/babel-traverse/test/fixtures/rename/parameter-default-6/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
5
packages/babel-traverse/test/fixtures/rename/parameter-default-6/output.js
vendored
Normal file
5
packages/babel-traverse/test/fixtures/rename/parameter-default-6/output.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
let a = "outside";
|
||||
|
||||
function n(g = (a = a) => {}) {
|
||||
let z = "inside";
|
||||
}
|
||||
9
packages/babel-traverse/test/fixtures/rename/parameter-default-6/plugin.js
vendored
Normal file
9
packages/babel-traverse/test/fixtures/rename/parameter-default-6/plugin.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
FunctionDeclaration(path) {
|
||||
path.scope.rename("a", "z");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
5
packages/babel-traverse/test/fixtures/rename/parameter-default-7/input.js
vendored
Normal file
5
packages/babel-traverse/test/fixtures/rename/parameter-default-7/input.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
let a = "outside";
|
||||
|
||||
function n(a, g = (a = a) => {}) {
|
||||
a = "inside";
|
||||
}
|
||||
3
packages/babel-traverse/test/fixtures/rename/parameter-default-7/options.json
vendored
Normal file
3
packages/babel-traverse/test/fixtures/rename/parameter-default-7/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
5
packages/babel-traverse/test/fixtures/rename/parameter-default-7/output.js
vendored
Normal file
5
packages/babel-traverse/test/fixtures/rename/parameter-default-7/output.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
let a = "outside";
|
||||
|
||||
function n(z, g = (a = a) => {}) {
|
||||
z = "inside";
|
||||
}
|
||||
9
packages/babel-traverse/test/fixtures/rename/parameter-default-7/plugin.js
vendored
Normal file
9
packages/babel-traverse/test/fixtures/rename/parameter-default-7/plugin.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
FunctionDeclaration(path) {
|
||||
path.scope.rename("a", "z");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
5
packages/babel-traverse/test/fixtures/rename/parameter-default-8/input.js
vendored
Normal file
5
packages/babel-traverse/test/fixtures/rename/parameter-default-8/input.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
let a = "outside";
|
||||
|
||||
function q(a, g = (b = a) => b) {
|
||||
g(a);
|
||||
}
|
||||
3
packages/babel-traverse/test/fixtures/rename/parameter-default-8/options.json
vendored
Normal file
3
packages/babel-traverse/test/fixtures/rename/parameter-default-8/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
5
packages/babel-traverse/test/fixtures/rename/parameter-default-8/output.js
vendored
Normal file
5
packages/babel-traverse/test/fixtures/rename/parameter-default-8/output.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
let a = "outside";
|
||||
|
||||
function q(z, g = (b = z) => b) {
|
||||
g(z);
|
||||
}
|
||||
9
packages/babel-traverse/test/fixtures/rename/parameter-default-8/plugin.js
vendored
Normal file
9
packages/babel-traverse/test/fixtures/rename/parameter-default-8/plugin.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
FunctionDeclaration(path) {
|
||||
path.scope.rename("a", "z");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
5
packages/babel-traverse/test/fixtures/rename/parameter-default-9/input.js
vendored
Normal file
5
packages/babel-traverse/test/fixtures/rename/parameter-default-9/input.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
let a = "outside";
|
||||
|
||||
function r(a, g = (a, b = a) => a) {
|
||||
g(a);
|
||||
}
|
||||
3
packages/babel-traverse/test/fixtures/rename/parameter-default-9/options.json
vendored
Normal file
3
packages/babel-traverse/test/fixtures/rename/parameter-default-9/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
5
packages/babel-traverse/test/fixtures/rename/parameter-default-9/output.js
vendored
Normal file
5
packages/babel-traverse/test/fixtures/rename/parameter-default-9/output.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
let a = "outside";
|
||||
|
||||
function r(z, g = (a, b = a) => a) {
|
||||
g(z);
|
||||
}
|
||||
9
packages/babel-traverse/test/fixtures/rename/parameter-default-9/plugin.js
vendored
Normal file
9
packages/babel-traverse/test/fixtures/rename/parameter-default-9/plugin.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
FunctionDeclaration(path) {
|
||||
path.scope.rename("a", "z");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -73,6 +73,25 @@ describe("scope", () => {
|
||||
).toBe("Identifier");
|
||||
});
|
||||
|
||||
describe("function parameter expression", function() {
|
||||
it("should not have visibility of declarations inside function body", () => {
|
||||
expect(
|
||||
getPath(
|
||||
`var a = "outside"; (function foo(b = a) { let a = "inside" })`,
|
||||
)
|
||||
.get("body.1.expression.params.0")
|
||||
.scope.getBinding("a").path.node.init.value,
|
||||
).toBe("outside");
|
||||
});
|
||||
it("should have visibility on parameter bindings", () => {
|
||||
expect(
|
||||
getPath(`var a = "outside"; (function foo(b = a, a = "inside") {})`)
|
||||
.get("body.1.expression.params.0")
|
||||
.scope.getBinding("a").path.node.right.value,
|
||||
).toBe("inside");
|
||||
});
|
||||
});
|
||||
|
||||
it("variable declaration", function() {
|
||||
expect(getPath("var foo = null;").scope.getBinding("foo").path.type).toBe(
|
||||
"VariableDeclarator",
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
isCatchClause,
|
||||
isBlockStatement,
|
||||
isScopable,
|
||||
isPattern,
|
||||
} from "./generated";
|
||||
|
||||
/**
|
||||
@ -18,5 +19,11 @@ export default function isScope(node: Object, parent: Object): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If a Pattern is an immediate descendent of a Function, it must be in the params.
|
||||
// Hence we skipped the parentKey === "params" check
|
||||
if (isPattern(node) && isFunction(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isScopable(node);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user