From 39bdecb119da13c6b2df7464863322adc49a1c9a Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Sun, 1 Nov 2015 04:39:31 +0000 Subject: [PATCH] fix async function remap helper from outputing incorrect calls causing wrong scoping - fixes #2708 - fixes #2715 --- CHANGELOG.md | 5 ++ .../async-to-generator/expression/expected.js | 11 ++- .../named-expression/actual.js | 2 - .../named-expression/expected.js | 13 ++-- .../no-parameters-and-no-id/actual.js | 3 + .../no-parameters-and-no-id/expected.js | 1 + .../async-to-generator/parameters/actual.js | 3 + .../async-to-generator/parameters/expected.js | 6 ++ .../async-to-generator/statement/expected.js | 11 ++- .../expression/expected.js | 12 ++- .../named-expression/actual.js | 2 - .../named-expression/expected.js | 12 +-- .../bluebird-coroutines/statement/expected.js | 12 ++- .../package.json | 3 +- .../src/index.js | 77 +++++++++++++++---- 15 files changed, 124 insertions(+), 49 deletions(-) create mode 100644 packages/babel-core/test/fixtures/transformation/async-to-generator/no-parameters-and-no-id/actual.js create mode 100644 packages/babel-core/test/fixtures/transformation/async-to-generator/no-parameters-and-no-id/expected.js create mode 100644 packages/babel-core/test/fixtures/transformation/async-to-generator/parameters/actual.js create mode 100644 packages/babel-core/test/fixtures/transformation/async-to-generator/parameters/expected.js diff --git a/CHANGELOG.md b/CHANGELOG.md index ad118e0e68..bd9d2d16db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,11 @@ _Note: Gaps between patch versions are faulty, broken or test releases._ See [CHANGELOG - 6to5](CHANGELOG-6to5.md) for the pre-4.0.0 version changelog. +## 6.0.15 + + * **Bug Fix** + * Fix async function remap helper from outputing incorrect calls causing wrong scoping. + ## 6.0.14 * **Spec Compliancy** diff --git a/packages/babel-core/test/fixtures/transformation/async-to-generator/expression/expected.js b/packages/babel-core/test/fixtures/transformation/async-to-generator/expression/expected.js index 41da03021d..a8a7685d12 100644 --- a/packages/babel-core/test/fixtures/transformation/async-to-generator/expression/expected.js +++ b/packages/babel-core/test/fixtures/transformation/async-to-generator/expression/expected.js @@ -1,5 +1,8 @@ -var foo = function () { - return babelHelpers.asyncToGenerator(function* () { +var foo = (function () { + var ref = babelHelpers.asyncToGenerator(function* () { var wat = yield bar(); - })(); -}; + }); + return function foo() { + return ref.apply(this, arguments); + }; +})(); diff --git a/packages/babel-core/test/fixtures/transformation/async-to-generator/named-expression/actual.js b/packages/babel-core/test/fixtures/transformation/async-to-generator/named-expression/actual.js index f2590da949..337183ceaa 100644 --- a/packages/babel-core/test/fixtures/transformation/async-to-generator/named-expression/actual.js +++ b/packages/babel-core/test/fixtures/transformation/async-to-generator/named-expression/actual.js @@ -1,5 +1,3 @@ var foo = async function bar() { console.log(bar); }; - -foo(); diff --git a/packages/babel-core/test/fixtures/transformation/async-to-generator/named-expression/expected.js b/packages/babel-core/test/fixtures/transformation/async-to-generator/named-expression/expected.js index 0cf977e389..e727401db9 100644 --- a/packages/babel-core/test/fixtures/transformation/async-to-generator/named-expression/expected.js +++ b/packages/babel-core/test/fixtures/transformation/async-to-generator/named-expression/expected.js @@ -1,7 +1,8 @@ -var foo = function () { - return babelHelpers.asyncToGenerator(function* bar() { +var foo = (function () { + var ref = babelHelpers.asyncToGenerator(function* bar() { console.log(bar); - })(); -}; - -foo(); + }); + return function foo() { + return ref.apply(this, arguments); + }; +})(); diff --git a/packages/babel-core/test/fixtures/transformation/async-to-generator/no-parameters-and-no-id/actual.js b/packages/babel-core/test/fixtures/transformation/async-to-generator/no-parameters-and-no-id/actual.js new file mode 100644 index 0000000000..ace10cfe9a --- /dev/null +++ b/packages/babel-core/test/fixtures/transformation/async-to-generator/no-parameters-and-no-id/actual.js @@ -0,0 +1,3 @@ +foo(async function () { + +}); diff --git a/packages/babel-core/test/fixtures/transformation/async-to-generator/no-parameters-and-no-id/expected.js b/packages/babel-core/test/fixtures/transformation/async-to-generator/no-parameters-and-no-id/expected.js new file mode 100644 index 0000000000..c2fa8ede7a --- /dev/null +++ b/packages/babel-core/test/fixtures/transformation/async-to-generator/no-parameters-and-no-id/expected.js @@ -0,0 +1 @@ +foo(babelHelpers.asyncToGenerator(function* () {})); diff --git a/packages/babel-core/test/fixtures/transformation/async-to-generator/parameters/actual.js b/packages/babel-core/test/fixtures/transformation/async-to-generator/parameters/actual.js new file mode 100644 index 0000000000..4509d445df --- /dev/null +++ b/packages/babel-core/test/fixtures/transformation/async-to-generator/parameters/actual.js @@ -0,0 +1,3 @@ +async function foo(bar) { + +} diff --git a/packages/babel-core/test/fixtures/transformation/async-to-generator/parameters/expected.js b/packages/babel-core/test/fixtures/transformation/async-to-generator/parameters/expected.js new file mode 100644 index 0000000000..a8012824ed --- /dev/null +++ b/packages/babel-core/test/fixtures/transformation/async-to-generator/parameters/expected.js @@ -0,0 +1,6 @@ +let foo = (function () { + var ref = babelHelpers.asyncToGenerator(function* foo(bar) {}); + return function foo(_x) { + return ref.apply(this, arguments); + }; +})(); diff --git a/packages/babel-core/test/fixtures/transformation/async-to-generator/statement/expected.js b/packages/babel-core/test/fixtures/transformation/async-to-generator/statement/expected.js index 9b407f49d8..063c0f4e12 100644 --- a/packages/babel-core/test/fixtures/transformation/async-to-generator/statement/expected.js +++ b/packages/babel-core/test/fixtures/transformation/async-to-generator/statement/expected.js @@ -1,5 +1,8 @@ -let foo = function foo() { - return babelHelpers.asyncToGenerator(function* foo() { +let foo = (function () { + var ref = babelHelpers.asyncToGenerator(function* foo() { var wat = yield bar(); - })(); -}; + }); + return function foo() { + return ref.apply(this, arguments); + }; +})(); diff --git a/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/expression/expected.js b/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/expression/expected.js index b0329029bb..1733da4a46 100644 --- a/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/expression/expected.js +++ b/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/expression/expected.js @@ -1,6 +1,10 @@ import { coroutine as _coroutine } from "bluebird"; -var foo = function () { - return _coroutine(function* () { +var foo = (function () { + var ref = _coroutine(function* () { var wat = yield bar(); - })(); -}; + }); + + return function foo() { + return ref.apply(this, arguments); + }; +})(); diff --git a/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/named-expression/actual.js b/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/named-expression/actual.js index f2590da949..337183ceaa 100644 --- a/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/named-expression/actual.js +++ b/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/named-expression/actual.js @@ -1,5 +1,3 @@ var foo = async function bar() { console.log(bar); }; - -foo(); diff --git a/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/named-expression/expected.js b/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/named-expression/expected.js index e7bc57ac50..5dfc5e1f0d 100644 --- a/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/named-expression/expected.js +++ b/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/named-expression/expected.js @@ -1,8 +1,10 @@ import { coroutine as _coroutine } from "bluebird"; -var foo = function () { - return _coroutine(function* bar() { +var foo = (function () { + var ref = _coroutine(function* bar() { console.log(bar); - })(); -}; + }); -foo(); + return function foo() { + return ref.apply(this, arguments); + }; +})(); diff --git a/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/statement/expected.js b/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/statement/expected.js index b74500ba7f..a2688cb525 100644 --- a/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/statement/expected.js +++ b/packages/babel-core/test/fixtures/transformation/bluebird-coroutines/statement/expected.js @@ -1,7 +1,11 @@ import { coroutine as _coroutine } from "bluebird"; -let foo = function foo() { - return _coroutine(function* foo() { +let foo = (function () { + var ref = _coroutine(function* foo() { var wat = yield bar(); - })(); -}; + }); + + return function foo() { + return ref.apply(this, arguments); + }; +})(); diff --git a/packages/babel-helper-remap-async-to-generator/package.json b/packages/babel-helper-remap-async-to-generator/package.json index 31595b1770..b4e8b88cf0 100644 --- a/packages/babel-helper-remap-async-to-generator/package.json +++ b/packages/babel-helper-remap-async-to-generator/package.json @@ -7,8 +7,9 @@ "main": "lib/index.js", "dependencies": { "babel-runtime": "^5.0.0", + "babel-template": "^6.0.14", "babel-types": "^6.0.14", "babel-traverse": "^6.0.14", "babel-helper-function-name": "^6.0.14" } -} \ No newline at end of file +} diff --git a/packages/babel-helper-remap-async-to-generator/src/index.js b/packages/babel-helper-remap-async-to-generator/src/index.js index 53f7b4811b..ff19aa9133 100644 --- a/packages/babel-helper-remap-async-to-generator/src/index.js +++ b/packages/babel-helper-remap-async-to-generator/src/index.js @@ -2,8 +2,18 @@ import type { NodePath } from "babel-traverse"; import nameFunction from "babel-helper-function-name"; +import template from "babel-template"; import * as t from "babel-types"; +let buildWrapper = template(` + (function () { + var ref = FUNCTION; + return function (PARAMS) { + return ref.apply(this, arguments); + }; + }) +`); + let awaitVisitor = { Function(path) { path.skip(); @@ -14,45 +24,78 @@ let awaitVisitor = { } }; -export default function (path: NodePath, callId: Object) { +function classMethod(path: NodePath, callId: Object) { let node = path.node; - if (node.generator) return; + let body = node.body; - if (path.isClassMethod()) { - node.async = false; + node.async = false; - let body = node.body; + let container = t.functionExpression(null, [], t.blockStatement(body.body), true); + container.shadow = true; + body.body = [ + t.returnStatement(t.callExpression( + t.callExpression(callId, [container]), + [] + )) + ]; +} - let container = t.functionExpression(null, [], t.blockStatement(body.body), true); - container.shadow = true; - body.body = [t.returnStatement(t.callExpression(t.callExpression(callId, [container]), []))]; - return; - } +function plainFunction(path: NodePath, callId: Object) { + let node = path.node; node.async = false; node.generator = true; path.traverse(awaitVisitor); - let container = t.functionExpression(null, [], t.blockStatement([ - t.returnStatement(t.callExpression(t.callExpression(callId, [node]), [])) - ])); - node.shadow = container; + let built = t.callExpression(callId, [node]); + let container = buildWrapper({ + FUNCTION: built, + PARAMS: node.params.map(() => path.scope.generateUidIdentifier("x")) + }).expression; + + let retFunction = container.body.body[1].argument; if (path.isFunctionDeclaration()) { let declar = t.variableDeclaration("let", [ - t.variableDeclarator(t.identifier(node.id.name), container) + t.variableDeclarator( + t.identifier(node.id.name), + t.callExpression(container, []) + ) ]); declar._blockHoist = true; nameFunction({ - node: container, + node: retFunction, parent: declar.declarations[0], scope: path.scope }); path.replaceWith(declar); } else { - path.replaceWith(container); + nameFunction({ + node: retFunction, + parent: path.parent, + scope: path.scope + }); + + if (retFunction.id || node.params.length) { + // we have an inferred function id or params so we need this wrapper + path.replaceWith(t.callExpression(container, [])); + } else { + // we can omit this wrapper as the conditions it protects for do not apply + path.replaceWith(built); + } + } +} + +export default function (path: NodePath, callId: Object) { + let node = path.node; + if (node.generator) return; + + if (path.isClassMethod()) { + return classMethod(path, callId); + } else { + return plainFunction(path, callId); } }