Fix scope of function body when var redeclares param (#11158)

* Fix scope of function body when var redeclares param

* Fix empty var declarations

* Apply suggestions
This commit is contained in:
Daryl Tan 2020-03-01 23:26:22 +08:00 committed by GitHub
parent a39beda58b
commit 9015fda3c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 140 additions and 4 deletions

View File

@ -18,7 +18,11 @@ const visitor = {
}, },
}; };
export default function(path: NodePath, scope = path.scope) { export default function(
path: NodePath,
scope = path.scope,
shouldHoistVariables = true,
) {
const { node } = path; const { node } = path;
const container = t.functionExpression( const container = t.functionExpression(
null, null,
@ -31,8 +35,9 @@ export default function(path: NodePath, scope = path.scope) {
let callee = container; let callee = container;
let args = []; let args = [];
// todo: only hoist if necessary if (shouldHoistVariables) {
hoistVariables(path, id => scope.push({ id })); hoistVariables(path, id => scope.push({ id }));
}
const state = { const state = {
foundThis: false, foundThis: false,

View File

@ -64,6 +64,31 @@ export default function convertFunctionParams(path, loose) {
for (let i = 0; i < params.length; i++) { for (let i = 0; i < params.length; i++) {
const param = params[i]; const param = params[i];
for (const name of Object.keys(param.getBindingIdentifiers())) {
const constantViolations = scope.bindings[name]?.constantViolations;
if (constantViolations) {
for (const redeclarator of constantViolations) {
const node = redeclarator.node;
// If a constant violation is a var or a function declaration,
// we first check to see if it's a var without an init.
// If so, we remove that declarator.
// Otherwise, we have to wrap it in an IIFE.
switch (node.type) {
case "VariableDeclarator":
if (node.init === null) {
redeclarator.remove();
} else {
state.iife = true;
}
break;
case "FunctionDeclaration":
state.iife = true;
break;
}
}
}
}
const paramIsAssignmentPattern = param.isAssignmentPattern(); const paramIsAssignmentPattern = param.isAssignmentPattern();
if (paramIsAssignmentPattern && (loose || node.kind === "set")) { if (paramIsAssignmentPattern && (loose || node.kind === "set")) {
const left = param.get("left"); const left = param.get("left");
@ -146,7 +171,8 @@ export default function convertFunctionParams(path, loose) {
path.ensureBlock(); path.ensureBlock();
if (state.iife) { if (state.iife) {
body.push(callDelegate(path, scope)); // we don't want to hoist the inner declarations up
body.push(callDelegate(path, scope, false));
path.set("body", t.blockStatement(body)); path.set("body", t.blockStatement(body));
} else { } else {
path.get("body").unshiftContainer("body", body); path.get("body").unshiftContainer("body", body);

View File

@ -0,0 +1,5 @@
function foo(a = 2) {
function a() {
}
}

View File

@ -0,0 +1,6 @@
function foo() {
var a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 2;
return function () {
function a() {}
}();
}

View File

@ -0,0 +1,6 @@
function f(a = 2, b = 3) {
var a, b = 4;
var a;
var b;
return a + b;
}

View File

@ -0,0 +1,8 @@
function f() {
var a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 2;
var b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 3;
return function () {
var b = 4;
return a + b;
}();
}

View File

@ -0,0 +1,5 @@
function f(a = 2, b = 3) {
var a;
var { a } = { a: 4 };
return a + b;
}

View File

@ -0,0 +1,11 @@
function f() {
var a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 2;
var b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 3;
return function () {
var _a = {
a: 4
},
a = _a.a;
return a + b;
}();
}

View File

@ -0,0 +1,5 @@
function foo({a, b}) {
var a = 3;
var c = 2;
var d = a + b + c;
}

View File

@ -0,0 +1,9 @@
function foo(_ref) {
var a = _ref.a,
b = _ref.b;
return function () {
var a = 3;
var c = 2;
var d = a + b + c;
}();
}

View File

@ -0,0 +1,5 @@
function foo([a, b]) {
var a = 3;
var c = 2;
var d = a + b + c;
}

View File

@ -0,0 +1,11 @@
function foo(_ref) {
var _ref2 = babelHelpers.slicedToArray(_ref, 2),
a = _ref2[0],
b = _ref2[1];
return function () {
var a = 3;
var c = 2;
var d = a + b + c;
}();
}

View File

@ -0,0 +1,8 @@
var x = 1
function foo(x, y = function () { x = 2 }) {
var x = 3
y()
expect(x).toBe(3);
}
foo()
expect(x).toBe(1);

View File

@ -0,0 +1,3 @@
function foo(a = 2) {
var a = 1;
}

View File

@ -0,0 +1,6 @@
function foo() {
var a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 2;
return function () {
var a = 1;
}();
}

View File

@ -0,0 +1,6 @@
function f(a = 2, b = 3) {
var { a } = { a: 4 };
var a;
var b;
return a + b;
}

View File

@ -0,0 +1,11 @@
function f() {
var a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 2;
var b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 3;
return function () {
var _a = {
a: 4
},
a = _a.a;
return a + b;
}();
}