From dadba0124958fbb60abd32ded165b76c7fac71e1 Mon Sep 17 00:00:00 2001 From: Vedant Roy Date: Sun, 9 Feb 2020 05:40:52 -0500 Subject: [PATCH] Fix export bindings not updated by 'for...in' and 'for...of' (#11074) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Correctly transpile export bindings for some for-of loops * Correctly transform non-destructured for of loops to update exported variables * Add tests * Don't replace entire for of loop * Correctly transform destructured for-of/for-in exports * Update exported variables in array pattern and more fixes * Refresh test output * Update tests and rebase on master * Refactor ForOf|ForIn visitor * Don't transform re-declared exported vars * Generate better name for loop id Co-Authored-By: Nicolò Ribaudo * Idiomatically generate UidIdentifier * Update scope after replacing loop declaration Co-authored-by: Nicolò Ribaudo --- .../src/rewrite-live-references.js | 36 ++++++++++ .../fixtures/misc/for-of-in-export/input.mjs | 22 +++++++ .../fixtures/misc/for-of-in-export/output.js | 65 +++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 packages/babel-plugin-transform-modules-commonjs/test/fixtures/misc/for-of-in-export/input.mjs create mode 100644 packages/babel-plugin-transform-modules-commonjs/test/fixtures/misc/for-of-in-export/output.js diff --git a/packages/babel-helper-module-transforms/src/rewrite-live-references.js b/packages/babel-helper-module-transforms/src/rewrite-live-references.js index 95f1daadd158..b98953f70662 100644 --- a/packages/babel-helper-module-transforms/src/rewrite-live-references.js +++ b/packages/babel-helper-module-transforms/src/rewrite-live-references.js @@ -306,4 +306,40 @@ const rewriteReferencesVisitor = { } }, }, + "ForOfStatement|ForInStatement"(path) { + const { scope, node } = path; + const { left } = node; + const { exported, scope: programScope } = this; + + if (!t.isVariableDeclaration(left)) { + let didTransform = false; + const bodyPath = path.get("body"); + const loopBodyScope = bodyPath.scope; + for (const name of Object.keys(t.getOuterBindingIdentifiers(left))) { + if ( + exported.get(name) && + programScope.getBinding(name) === scope.getBinding(name) + ) { + didTransform = true; + if (loopBodyScope.hasOwnBinding(name)) { + loopBodyScope.rename(name); + } + } + } + if (!didTransform) { + return; + } + const newLoopId = scope.generateUidIdentifierBasedOnNode(left); + bodyPath.unshiftContainer( + "body", + t.expressionStatement(t.assignmentExpression("=", left, newLoopId)), + ); + path + .get("left") + .replaceWith( + t.variableDeclaration("let", [t.variableDeclarator(newLoopId)]), + ); + scope.registerDeclaration(path.get("left")); + } + }, }; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/misc/for-of-in-export/input.mjs b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/misc/for-of-in-export/input.mjs new file mode 100644 index 000000000000..fe09208eea2c --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/misc/for-of-in-export/input.mjs @@ -0,0 +1,22 @@ +export let foo; +export {foo as bar} + +for (foo of []) {} +for (foo in []) {} +for (foo of []) { + let foo; +} +for ({foo} of []) {} +for ({foo} of []) { + let foo; +} +for ({test: {foo}} of []) {} +for ([foo, [...foo]] of []) {} +for ([foo, [...foo]] of []) { + let foo; +} + +{ + let foo; + for(foo of []) {} +} \ No newline at end of file diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/misc/for-of-in-export/output.js b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/misc/for-of-in-export/output.js new file mode 100644 index 000000000000..bb8330350160 --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/misc/for-of-in-export/output.js @@ -0,0 +1,65 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.bar = exports.foo = void 0; +let foo; +exports.bar = exports.foo = foo; + +for (let _foo of []) { + exports.bar = exports.foo = foo = _foo; +} + +for (let _foo2 in []) { + exports.bar = exports.foo = foo = _foo2; +} + +for (let _foo4 of []) { + exports.bar = exports.foo = foo = _foo4; + + let _foo3; +} + +for (let _foo5 of []) { + ({ + foo + } = _foo5); + exports.bar = exports.foo = foo; +} + +for (let _foo7 of []) { + ({ + foo + } = _foo7); + exports.bar = exports.foo = foo; + + let _foo6; +} + +for (let _test of []) { + ({ + test: { + foo + } + } = _test); + exports.bar = exports.foo = foo; +} + +for (let _ref of []) { + [foo, [...foo]] = _ref; + exports.bar = exports.foo = foo; +} + +for (let _ref2 of []) { + [foo, [...foo]] = _ref2; + exports.bar = exports.foo = foo; + + let _foo8; +} + +{ + let foo; + + for (foo of []) {} +}