Do not remove let bindings even they are wrapped in closure (#10343)

* fix: should not remove let binding even it is wrapped in closure

Fixes #10339

* fix: remove bindings defined in blockScope when wrapped in closure

* Move test assertions to the top level to ensure that they run
This commit is contained in:
Huáng Jùnliàng 2019-10-08 13:43:12 -04:00 committed by Nicolò Ribaudo
parent b0acfb24dd
commit 563874c06c
5 changed files with 76 additions and 5 deletions

View File

@ -441,22 +441,25 @@ class BlockScoping {
} }
updateScopeInfo(wrappedInClosure) { updateScopeInfo(wrappedInClosure) {
const scope = this.scope; const blockScope = this.blockPath.scope;
const parentScope = scope.getFunctionParent() || scope.getProgramParent(); const parentScope =
blockScope.getFunctionParent() || blockScope.getProgramParent();
const letRefs = this.letReferences; const letRefs = this.letReferences;
for (const key of Object.keys(letRefs)) { for (const key of Object.keys(letRefs)) {
const ref = letRefs[key]; const ref = letRefs[key];
const binding = scope.getBinding(ref.name); const binding = blockScope.getBinding(ref.name);
if (!binding) continue; if (!binding) continue;
if (binding.kind === "let" || binding.kind === "const") { if (binding.kind === "let" || binding.kind === "const") {
binding.kind = "var"; binding.kind = "var";
if (wrappedInClosure) { if (wrappedInClosure) {
scope.removeBinding(ref.name); if (blockScope.hasOwnBinding(ref.name)) {
blockScope.removeBinding(ref.name);
}
} else { } else {
scope.moveBindingTo(ref.name, parentScope); blockScope.moveBindingTo(ref.name, parentScope);
} }
} }
} }

View File

@ -0,0 +1,38 @@
const code = multiline([
"for (const {foo, ...bar} of { bar: [] }) {",
"() => foo;",
"const [qux] = bar;",
"try {} catch (e) {",
"let quux = qux;",
"}",
"}"
]);
let programPath;
let forOfPath;
let functionPath;
transform(code, {
configFile: false,
plugins: [
"../../../../lib",
{
post({ path }) {
programPath = path;
path.traverse({
ForOfStatement(path) { forOfPath = path },
FunctionExpression(path) { functionPath = path }
});
}
}
]
});
expect(Object.keys(programPath.scope.bindings)).toEqual(["foo", "bar"]);
// for declarations should be transformed to for bindings
expect(forOfPath.scope.bindings).toEqual({});
// The body should be wrapped into closure
expect(forOfPath.get("body").scope.bindings).toEqual({});
expect(Object.keys(functionPath.scope.bindings)).toEqual(["foo", "bar", "qux", "quux"]);

View File

@ -0,0 +1,7 @@
for (const {foo, ...bar} of {}) {
() => foo;
const [qux] = bar;
try {} catch (e) {
const quux = qux;
}
}

View File

@ -0,0 +1,3 @@
{
"plugins": ["transform-block-scoping", ["proposal-object-rest-spread", { "loose": true }]]
}

View File

@ -0,0 +1,20 @@
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
var _loop = function (foo, bar) {
() => foo;
var [qux] = bar;
try {} catch (e) {
var quux = qux;
}
};
for (var _ref of {}) {
var {
foo
} = _ref,
bar = _objectWithoutPropertiesLoose(_ref, ["foo"]);
_loop(foo, bar);
}