diff --git a/lib/babel/transformation/file.js b/lib/babel/transformation/file.js index e87042c47c..5fe49c3f15 100644 --- a/lib/babel/transformation/file.js +++ b/lib/babel/transformation/file.js @@ -59,7 +59,8 @@ File.helpers = [ "object-destructuring-empty", "temporal-undefined", "temporal-assert-defined", - "tail-call" + "tail-call", + "self-global" ]; File.validOptions = [ diff --git a/lib/babel/transformation/templates/named-func.js b/lib/babel/transformation/templates/named-func.js new file mode 100644 index 0000000000..85ada1748f --- /dev/null +++ b/lib/babel/transformation/templates/named-func.js @@ -0,0 +1,7 @@ +(function () { + function GET_OUTER_ID() { + return ID; + } + + return FUNCTION; +})() \ No newline at end of file diff --git a/lib/babel/transformation/transformers/index.js b/lib/babel/transformation/transformers/index.js index 3631235068..0b2eaad9f3 100644 --- a/lib/babel/transformation/transformers/index.js +++ b/lib/babel/transformation/transformers/index.js @@ -91,6 +91,7 @@ module.exports = { "spec.typeofSymbol": require("./spec/typeof-symbol"), "spec.undefinedToVoid": require("./spec/undefined-to-void"), + "spec.functionName": require("./spec/function-name"), _moduleFormatter: require("./internal/module-formatter"), diff --git a/lib/babel/transformation/transformers/spec/function-name.js b/lib/babel/transformation/transformers/spec/function-name.js new file mode 100644 index 0000000000..3541f8ab42 --- /dev/null +++ b/lib/babel/transformation/transformers/spec/function-name.js @@ -0,0 +1,53 @@ +"use strict"; + +var t = require("../../../types"); +var util = require("../../../util"); + +var propertyFunctionVisitor = { + enter: function (node, parent, scope, state, file) { + if (t.isReferencedIdentifier(node, parent, { name: state.name }) && scope.getBindingIdentifier(node.name) === state.binding) { + return state.getOuter(); + } + } +}; + +exports.FunctionExpression = function (node, parent, scope, file) { + if (node.id) return; + var id; + if (t.isProperty(parent)) { + id = parent.key; + } else if (t.isVariableDeclarator(parent)) { + id = parent.id; + } else { + return; + } + var binding = scope.getBindingIdentifier(id.name); + var outerId, selfGlobalId; + scope.traverse(node, propertyFunctionVisitor, { + name: id.name, + binding: binding, + + getOuter: function () { + if (!binding) { + return t.memberExpression( + selfGlobalId || (selfGlobalId = file.addHelper("self-global")), + id + ); + } + return t.callExpression( + outerId || (outerId = scope.generateUidIdentifier("getOuter")), + [] + ); + } + }); + node.id = id; + if (outerId) { + return util.template("named-func", { + GET_OUTER_ID: outerId, + ID: id, + FUNCTION: node + }); + } +}; + +exports.optional = true; diff --git a/test/fixtures/transformation/spec-function-name/actual.js b/test/fixtures/transformation/spec-function-name/actual.js new file mode 100644 index 0000000000..ee9d714601 --- /dev/null +++ b/test/fixtures/transformation/spec-function-name/actual.js @@ -0,0 +1,27 @@ +var obj = { + f: function () { + (function f() { + console.log(f); + })(); + }, + + g: function () { + console.log(g); + }, + + h: function () { + console.log(h); + }, + + m: function () { + doSmth(); + } +}; + +var f = function () { + console.log(f, g); +}; + +var g = function () { + doSmth(); +}; diff --git a/test/fixtures/transformation/spec-function-name/expected.js b/test/fixtures/transformation/spec-function-name/expected.js new file mode 100644 index 0000000000..3faa582c9e --- /dev/null +++ b/test/fixtures/transformation/spec-function-name/expected.js @@ -0,0 +1,42 @@ +"use strict"; + +var _selfGlobal = typeof global === "undefined" ? self : global; +var obj = { + f: function f() { + (function f() { + console.log(f); + })(); + }, + + g: (function () { + function _getOuter() { + return g; + } + + return function g() { + console.log(_getOuter()); + }; + })(), + + h: function h() { + console.log(_selfGlobal.h); + }, + + m: function m() { + doSmth(); + } +}; + +var f = (function () { + function _getOuter() { + return f; + } + + return function f() { + console.log(_getOuter(), g); + }; +})(); + +var g = function g() { + doSmth(); +}; diff --git a/test/fixtures/transformation/spec-function-name/options.json b/test/fixtures/transformation/spec-function-name/options.json new file mode 100644 index 0000000000..e9c4354c1b --- /dev/null +++ b/test/fixtures/transformation/spec-function-name/options.json @@ -0,0 +1,3 @@ +{ + "whitelist": ["spec.functionName"] +}