diff --git a/packages/babel-plugin-transform-for-of/src/index.ts b/packages/babel-plugin-transform-for-of/src/index.ts index 732d5d2091f0..b574640d7c5a 100644 --- a/packages/babel-plugin-transform-for-of/src/index.ts +++ b/packages/babel-plugin-transform-for-of/src/index.ts @@ -1,5 +1,6 @@ import { declare } from "@babel/helper-plugin-utils"; import { template, types as t } from "@babel/core"; +import type { NodePath } from "@babel/traverse"; import transformWithoutHelper from "./no-helper-implementation"; @@ -9,6 +10,28 @@ export interface Options { loose?: boolean; } +function buildLoopBody( + path: NodePath, + declar: t.Statement, + newBody?: t.Statement | t.Expression, +) { + let block; + const bodyPath = path.get("body"); + const body = newBody ?? bodyPath.node; + if ( + t.isBlockStatement(body) && + Object.keys(path.getBindingIdentifiers()).some(id => + bodyPath.scope.hasOwnBinding(id), + ) + ) { + block = t.blockStatement([declar, body]); + } else { + block = t.toBlock(body); + block.body.unshift(declar); + } + return block; +} + export default declare((api, options: Options) => { api.assertVersion(7); @@ -90,20 +113,6 @@ export default declare((api, options: Options) => { ); } - let blockBody; - const body = path.get("body"); - if ( - body.isBlockStatement() && - Object.keys(path.getBindingIdentifiers()).some(id => - body.scope.hasOwnBinding(id), - ) - ) { - blockBody = t.blockStatement([assignment, body.node]); - } else { - blockBody = t.toBlock(body.node); - blockBody.body.unshift(assignment); - } - path.replaceWith( t.forStatement( t.variableDeclaration("let", inits), @@ -113,7 +122,7 @@ export default declare((api, options: Options) => { t.memberExpression(t.cloneNode(array), t.identifier("length")), ), t.updateExpression("++", t.cloneNode(i)), - blockBody, + buildLoopBody(path, assignment), ), ); }, @@ -167,7 +176,6 @@ export default declare((api, options: Options) => { }) as t.For; t.inherits(loop, node); - t.ensureBlock(loop); const iterationValue = t.memberExpression( t.cloneNode(right), @@ -175,20 +183,19 @@ export default declare((api, options: Options) => { true, ); + let declar; const left = node.left; if (t.isVariableDeclaration(left)) { left.declarations[0].init = iterationValue; - // @ts-expect-error todo(flow->ts): - loop.body.body.unshift(left); + declar = left; } else { - // @ts-expect-error todo(flow->ts): - loop.body.body.unshift( - t.expressionStatement( - t.assignmentExpression("=", left, iterationValue), - ), + declar = t.expressionStatement( + t.assignmentExpression("=", left, iterationValue), ); } + loop.body = buildLoopBody(path, declar, loop.body); + return loop; } @@ -234,11 +241,6 @@ export default declare((api, options: Options) => { ); } - // ensure that it's a block so we can take all its statements - path.ensureBlock(); - - (node.body as t.BlockStatement).body.unshift(declar); - const nodes = builder.build({ CREATE_ITERATOR_HELPER: state.addHelper(builder.helper), ITERATOR_HELPER: scope.generateUidIdentifier("iterator"), @@ -247,7 +249,7 @@ export default declare((api, options: Options) => { : null, STEP_KEY: t.identifier(stepKey), OBJECT: node.right, - BODY: node.body, + BODY: buildLoopBody(path, declar), }); const container = builder.getContainer(nodes); diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/for-of-as-array/for-of-redeclaration-in-body/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/for-of-as-array/for-of-redeclaration-in-body/input.js index ded052290862..8073f40492f8 100644 --- a/packages/babel-plugin-transform-for-of/test/fixtures/for-of-as-array/for-of-redeclaration-in-body/input.js +++ b/packages/babel-plugin-transform-for-of/test/fixtures/for-of-as-array/for-of-redeclaration-in-body/input.js @@ -1,3 +1,7 @@ for (const elm of array) { const elm = 2; } + +for (let x of []) { + let x = 1; +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/for-of-as-array/for-of-redeclaration-in-body/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/for-of-as-array/for-of-redeclaration-in-body/output.js index f05d069d547d..824a04ef70bd 100644 --- a/packages/babel-plugin-transform-for-of/test/fixtures/for-of-as-array/for-of-redeclaration-in-body/output.js +++ b/packages/babel-plugin-transform-for-of/test/fixtures/for-of-as-array/for-of-redeclaration-in-body/output.js @@ -4,3 +4,10 @@ for (let _i = 0, _array = array; _i < _array.length; _i++) { const elm = 2; } } + +for (let _i2 = 0, _ref = []; _i2 < _ref.length; _i2++) { + let x = _ref[_i2]; + { + let x = 1; + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/loose/for-of-redeclaration-in-body/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/loose/for-of-redeclaration-in-body/input.js new file mode 100644 index 000000000000..abecc3bc5401 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/loose/for-of-redeclaration-in-body/input.js @@ -0,0 +1,9 @@ +for (let x of y) { + let x = 1; + let y = 2; +} + +for (let x of []) { + let x = 1; + let y = 2; +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/loose/for-of-redeclaration-in-body/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/loose/for-of-redeclaration-in-body/output.js new file mode 100644 index 000000000000..0947395ec708 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/loose/for-of-redeclaration-in-body/output.js @@ -0,0 +1,15 @@ +for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(y), _step; !(_step = _iterator()).done;) { + let x = _step.value; + { + let x = 1; + let y = 2; + } +} + +for (var _i = 0, _arr = []; _i < _arr.length; _i++) { + let x = _arr[_i]; + { + let x = 1; + let y = 2; + } +}