diff --git a/lib/6to5/transformation/modules/system.js b/lib/6to5/transformation/modules/system.js index e0bd3ef35f..9d14b5cfcc 100644 --- a/lib/6to5/transformation/modules/system.js +++ b/lib/6to5/transformation/modules/system.js @@ -15,8 +15,13 @@ function SystemFormatter(file) { util.inherits(SystemFormatter, AMDFormatter); -SystemFormatter.prototype._exportsWildcard = function (objectIdentifier) { - var leftIdentifier = t.identifier("i"); +SystemFormatter.prototype._addImportSource = function (node, exportNode) { + node._importSource = exportNode.source && exportNode.source.value; + return node; +}; + +SystemFormatter.prototype._exportsWildcard = function (objectIdentifier, node) { + var leftIdentifier = this.file.generateUidIdentifier("key"); var valIdentifier = t.memberExpression(objectIdentifier, leftIdentifier, true); var left = t.variableDeclaration("var", [ @@ -29,11 +34,12 @@ SystemFormatter.prototype._exportsWildcard = function (objectIdentifier) { this.buildExportCall(leftIdentifier, valIdentifier) ]); - return t.forInStatement(left, right, block); + return this._addImportSource(t.forInStatement(left, right, block), node); }; -SystemFormatter.prototype._exportsAssign = function (id, init) { - return this.buildExportCall(t.literal(id.name), init, true); +SystemFormatter.prototype._exportsAssign = function (id, init, node) { + var call = this.buildExportCall(t.literal(id.name), init, true); + return this._addImportSource(call, node); }; SystemFormatter.prototype.remapExportAssignment = function (node) { @@ -49,28 +55,53 @@ SystemFormatter.prototype.buildExportCall = function (id, init, isStatement) { } }; -SystemFormatter.prototype.buildRunnerSetters = function () { - return t.arrayExpression(_.map(this.ids, function (uid) { - var moduleIdentifier = t.identifier("m"); +SystemFormatter.prototype.importSpecifier = function (specifier, node, nodes) { + AMDFormatter.prototype.importSpecifier.apply(this, arguments); + this._addImportSource(_.last(nodes), node); +}; - return t.functionExpression(null, [moduleIdentifier], t.blockStatement([ - t.assignmentExpression("=", uid, moduleIdentifier) - ])); +SystemFormatter.prototype.buildRunnerSetters = function (block, hoistDeclarators) { + return t.arrayExpression(_.map(this.ids, function (uid, source) { + var nodes = []; + + traverse(block, { + enter: function (node) { + if (node._importSource === source) { + if (t.isVariableDeclaration(node)) { + _.each(node.declarations, function (declar) { + hoistDeclarators.push(t.variableDeclarator(declar.id)); + nodes.push(t.expressionStatement( + t.assignmentExpression("=", declar.id, declar.init) + )); + }); + } else { + nodes.push(node); + } + + this.remove(); + } + } + }); + + return t.functionExpression(null, [uid], t.blockStatement(nodes)); })); }; SystemFormatter.prototype.transform = function (ast) { var program = ast.program; + var hoistDeclarators = []; var moduleName = this.getModuleName(); var moduleNameLiteral = t.literal(moduleName); + var block = t.blockStatement(program.body); + var runner = util.template("system", { MODULE_NAME: moduleNameLiteral, MODULE_DEPENDENCIES: t.arrayExpression(this.buildDependencyLiterals()), EXPORT_IDENTIFIER: this.exportIdentifier, - SETTERS: this.buildRunnerSetters(), - EXECUTE: t.functionExpression(null, [], t.blockStatement(program.body)) + SETTERS: this.buildRunnerSetters(block, hoistDeclarators), + EXECUTE: t.functionExpression(null, [], block) }, true); var handlerBody = runner.expression.arguments[2].body.body; @@ -78,8 +109,55 @@ SystemFormatter.prototype.transform = function (ast) { var returnStatement = handlerBody.pop(); + // hoist up all variable declarations + traverse(block, { + enter: function (node, parent, scope) { + if (t.isFunction(node)) { + // nothing inside is accessible + return this.stop(); + } + + if (t.isVariableDeclaration(node)) { + if (node.kind !== "var" && !t.isProgram(parent)) { // let, const + // can't be accessed + return; + } + + var nodes = []; + + _.each(node.declarations, function (declar) { + hoistDeclarators.push(t.variableDeclarator(declar.id)); + if (declar.init) { + // no initializer so we can just hoist it as-is + var assign = t.expressionStatement(t.assignmentExpression("=", declar.id, declar.init)); + nodes.push(assign); + } + }); + + // for (var i in test) + // for (var i = 0;;) + if (t.isFor(parent)) { + if (parent.left === node) { + return node.declarations[0].id; + } + + if (parent.init === node) { + return t.toSequenceExpression(nodes, scope); + } + } + + return nodes; + } + } + }); + if (hoistDeclarators.length) { + var hoistDeclar = t.variableDeclaration("var", hoistDeclarators); + hoistDeclar._blockHoist = true; + handlerBody.unshift(hoistDeclar); + } + // hoist up function declarations for circular references - traverse(program, { + traverse(block, { enter: function (node) { if (t.isFunction(node)) this.stop(); @@ -90,12 +168,6 @@ SystemFormatter.prototype.transform = function (ast) { } }); - if (!_.isEmpty(this.ids)) { - handlerBody.push(t.variableDeclaration("var", _.map(this.ids, function (uid) { - return t.variableDeclarator(uid); - }))); - } - handlerBody.push(returnStatement); program.body = [runner]; diff --git a/test/fixtures/transformation/es6-modules-system/exports-default/expected.js b/test/fixtures/transformation/es6-modules-system/exports-default/expected.js index 6c2b8c396e..f35e77ee06 100644 --- a/test/fixtures/transformation/es6-modules-system/exports-default/expected.js +++ b/test/fixtures/transformation/es6-modules-system/exports-default/expected.js @@ -1,4 +1,5 @@ System.register([], function (_export) { + var Foo; _export("default", foo); function foo() {} @@ -19,7 +20,7 @@ System.register([], function (_export) { _export("default", function () {}); - var Foo = function Foo() {}; + Foo = function Foo() {}; _export("default", Foo); } diff --git a/test/fixtures/transformation/es6-modules-system/exports-from/expected.js b/test/fixtures/transformation/es6-modules-system/exports-from/expected.js index 47083a27f1..b653c04c75 100644 --- a/test/fixtures/transformation/es6-modules-system/exports-from/expected.js +++ b/test/fixtures/transformation/es6-modules-system/exports-from/expected.js @@ -1,12 +1,10 @@ System.register(["foo"], function (_export) { - var _foo; return { - setters: [function (m) { - _foo = m - - for (var i in _foo) { - _export(i, _foo[i]) + setters: [function (_foo) { + for (var _key in _foo) { + _export(_key, _foo[_key]) } + _export("foo", _foo.foo); _export("foo", _foo.foo); @@ -20,7 +18,6 @@ System.register(["foo"], function (_export) { _export("default", _foo.foo); _export("bar", _foo.bar); - }], execute: function () { "use strict"; diff --git a/test/fixtures/transformation/es6-modules-system/exports-variable/expected.js b/test/fixtures/transformation/es6-modules-system/exports-variable/expected.js index 984e2fb108..60dbd28db2 100644 --- a/test/fixtures/transformation/es6-modules-system/exports-variable/expected.js +++ b/test/fixtures/transformation/es6-modules-system/exports-variable/expected.js @@ -1,4 +1,5 @@ System.register([], function (_export) { + var foo, foo2, foo3, foo4, foo5, foo6, foo8; _export("foo7", foo7); function foo7() {} @@ -7,13 +8,13 @@ System.register([], function (_export) { execute: function () { "use strict"; - var foo = _export("foo", 1); - var foo2 = _export("foo2", function () {}); - var foo3 = _export("foo3", undefined); - var foo4 = _export("foo4", 2); - var foo5 = _export("foo5", undefined); - var foo6 = _export("foo6", 3); - var foo8 = function foo8() {}; + foo = _export("foo", 1); + foo2 = _export("foo2", function () {}); + foo3 = _export("foo3", undefined); + foo4 = _export("foo4", 2); + foo5 = _export("foo5", undefined); + foo6 = _export("foo6", 3); + foo8 = function foo8() {}; _export("foo8", foo8); } diff --git a/test/fixtures/transformation/es6-modules-system/hoist-function-exports/expected.js b/test/fixtures/transformation/es6-modules-system/hoist-function-exports/expected.js index e74627e56e..68d36802b2 100644 --- a/test/fixtures/transformation/es6-modules-system/hoist-function-exports/expected.js +++ b/test/fixtures/transformation/es6-modules-system/hoist-function-exports/expected.js @@ -1,24 +1,20 @@ System.register(["./evens"], function (_export) { - var p; - + var isEven, p, isOdd; _export("nextOdd", nextOdd); function nextOdd(n) { return _export("p", p = isEven(n) ? n + 1 : n + 2); } - var _evens; return { - setters: [function (m) { - _evens = m + setters: [function (_evens) { + isEven = _evens.isEven; }], execute: function () { "use strict"; - var isEven = _evens.isEven; - _export("p", p = 5); - - var isOdd = _export("isOdd", (function (isEven) { + p = _export("p", 5); + isOdd = _export("isOdd", (function (isEven) { return function (n) { return !isEven(n); }; diff --git a/test/fixtures/transformation/es6-modules-system/imports-default/expected.js b/test/fixtures/transformation/es6-modules-system/imports-default/expected.js index 739bb3d898..22870cf020 100644 --- a/test/fixtures/transformation/es6-modules-system/imports-default/expected.js +++ b/test/fixtures/transformation/es6-modules-system/imports-default/expected.js @@ -1,14 +1,12 @@ -System.register([], function (_export) { - var _foo; +System.register(["foo"], function (_export) { + var foo, foo; return { - setters: [function (m) { - _foo = m + setters: [function (_foo) { + foo = _foo["default"]; + foo = _foo["default"]; }], execute: function () { "use strict"; - - var foo = _foo["default"]; - var foo = _foo["default"]; } }; }); diff --git a/test/fixtures/transformation/es6-modules-system/imports-glob/expected.js b/test/fixtures/transformation/es6-modules-system/imports-glob/expected.js index 90b8ff9676..4d4116a967 100644 --- a/test/fixtures/transformation/es6-modules-system/imports-glob/expected.js +++ b/test/fixtures/transformation/es6-modules-system/imports-glob/expected.js @@ -1,13 +1,11 @@ System.register(["foo"], function (_export) { - var _foo; + var foo; return { - setters: [function (m) { - _foo = m + setters: [function (_foo) { + foo = _foo; }], execute: function () { "use strict"; - - var foo = _foo; } }; -}); \ No newline at end of file +}); diff --git a/test/fixtures/transformation/es6-modules-system/imports-mixing/expected.js b/test/fixtures/transformation/es6-modules-system/imports-mixing/expected.js index fa48c8ee8a..a460c9428d 100644 --- a/test/fixtures/transformation/es6-modules-system/imports-mixing/expected.js +++ b/test/fixtures/transformation/es6-modules-system/imports-mixing/expected.js @@ -1,14 +1,12 @@ System.register(["foo"], function (_export) { - var _foo; + var foo, xyz; return { - setters: [function (m) { - _foo = m + setters: [function (_foo) { + foo = _foo["default"]; + xyz = _foo.baz; }], execute: function () { "use strict"; - - var foo = _foo["default"]; - var xyz = _foo.baz; } }; }); diff --git a/test/fixtures/transformation/es6-modules-system/imports-named/expected.js b/test/fixtures/transformation/es6-modules-system/imports-named/expected.js index 6a0ac43741..ecfffa1e63 100644 --- a/test/fixtures/transformation/es6-modules-system/imports-named/expected.js +++ b/test/fixtures/transformation/es6-modules-system/imports-named/expected.js @@ -1,18 +1,16 @@ System.register(["foo"], function (_export) { - var _foo; + var bar, bar, baz, baz, baz, xyz; return { - setters: [function (m) { - _foo = m + setters: [function (_foo) { + bar = _foo.bar; + bar = _foo.bar; + baz = _foo.baz; + baz = _foo.bar; + baz = _foo.bar; + xyz = _foo.xyz; }], execute: function () { "use strict"; - - var bar = _foo.bar; - var bar = _foo.bar; - var baz = _foo.baz; - var baz = _foo.bar; - var baz = _foo.bar; - var xyz = _foo.xyz; } }; -}); \ No newline at end of file +}); diff --git a/test/fixtures/transformation/es6-modules-system/imports/expected.js b/test/fixtures/transformation/es6-modules-system/imports/expected.js index 97413af25b..d83799ca9e 100644 --- a/test/fixtures/transformation/es6-modules-system/imports/expected.js +++ b/test/fixtures/transformation/es6-modules-system/imports/expected.js @@ -1,15 +1,8 @@ System.register(["foo", "foo-bar", "./directory/foo-bar"], function (_export) { - var _foo, _fooBar, _directoryFooBar; return { - setters: [function (m) { - _foo = m - }, function (m) { - _fooBar = m - }, function (m) { - _directoryFooBar = m - }], + setters: [function (_foo) {}, function (_fooBar) {}, function (_directoryFooBar) {}], execute: function () { "use strict"; } }; -}); \ No newline at end of file +}); diff --git a/test/fixtures/transformation/es6-modules-system/overview/expected.js b/test/fixtures/transformation/es6-modules-system/overview/expected.js index f88db05b90..67fbbc561d 100644 --- a/test/fixtures/transformation/es6-modules-system/overview/expected.js +++ b/test/fixtures/transformation/es6-modules-system/overview/expected.js @@ -1,24 +1,18 @@ System.register(["foo", "foo-bar", "./directory/foo-bar"], function (_export) { - var _foo, _fooBar, _directoryFooBar; + var foo, foo, bar, bar, test; return { - setters: [function (m) { - _foo = m - }, function (m) { - _fooBar = m - }, function (m) { - _directoryFooBar = m - }], + setters: [function (_foo) { + foo = _foo["default"]; + foo = _foo; + bar = _foo.bar; + bar = _foo.foo; + }, function (_fooBar) {}, function (_directoryFooBar) {}], execute: function () { "use strict"; - var foo = _foo["default"]; - var foo = _foo; - var bar = _foo.bar; - var bar = _foo.foo; _export("test", test); - var test = _export("test", 5); - + test = _export("test", 5); _export("default", test); } }; diff --git a/test/fixtures/transformation/es6-modules-system/remap/expected.js b/test/fixtures/transformation/es6-modules-system/remap/expected.js index 44b7d1f1f8..efe3cec743 100644 --- a/test/fixtures/transformation/es6-modules-system/remap/expected.js +++ b/test/fixtures/transformation/es6-modules-system/remap/expected.js @@ -1,10 +1,11 @@ System.register([], function (_export) { + var test; return { setters: [], execute: function () { "use strict"; - var test = _export("test", 2); + test = _export("test", 2); _export("test", test = 5); _export("test", test += 1);