diff --git a/src/acorn/src/statement.js b/src/acorn/src/statement.js index be8e33786f..1fdd968549 100755 --- a/src/acorn/src/statement.js +++ b/src/acorn/src/statement.js @@ -560,12 +560,22 @@ pp.parseExport = function(node) { // export * from '...' if (this.eat(tt.star)) { if (this.options.features["es7.exportExtensions"] && this.eatContextual("as")) { - node.exported = this.parseIdent() + let specifier = this.startNode() + specifier.exported = this.parseIdent() + node.specifiers = [this.finishNode(specifier, "ExportNamespaceSpecifier")] + this.parseExportSpecifiersMaybe(node) + this.parseExportFrom(node) + } else { + this.parseExportFrom(node) + return this.finishNode(node, "ExportAllDeclaration") } + } else if (this.isExportDefaultSpecifier()) { + let specifier = this.startNode() + specifier.exported = this.parseIdent(true) + node.specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")] + this.parseExportSpecifiersMaybe(node) this.parseExportFrom(node) - return this.finishNode(node, "ExportAllDeclaration") - } - if (this.eat(tt._default)) { // export default ... + } else if (this.eat(tt._default)) { // export default ... let expr = this.parseMaybeAssign() let needsSemi = true if (expr.type == "FunctionExpression" || @@ -581,16 +591,10 @@ pp.parseExport = function(node) { if (needsSemi) this.semicolon() this.checkExport(node) return this.finishNode(node, "ExportDefaultDeclaration") - } - // export var|const|let|function|class ... - if (this.type.keyword || this.shouldParseExportDeclaration()) { + } else if (this.type.keyword || this.shouldParseExportDeclaration()) { node.declaration = this.parseStatement(true) node.specifiers = [] node.source = null - } else if (this.type === tt.name) { - node.exported = this.parseIdent() - this.parseExportFrom(node) - return this.finishNode(node, "ExportNamespaceDeclaration") } else { // export { x, y as z } [from '...'] node.declaration = null node.specifiers = this.parseExportSpecifiers() @@ -605,6 +609,25 @@ pp.parseExport = function(node) { return this.finishNode(node, "ExportNamedDeclaration") } +pp.isExportDefaultSpecifier = function () { + if (this.type === tt.name) { + return this.value !== "type" && this.value !== "async" + } + + if (this.type !== tt._default) { + return false + } + + var lookahead = this.lookahead() + return lookahead.type === tt.comma || (lookahead.type === tt.name && lookahead.value === "from") +} + +pp.parseExportSpecifiersMaybe = function (node) { + if (this.eat(tt.comma)) { + node.specifiers = node.specifiers.concat(this.parseExportSpecifiers()) + } +} + pp.parseExportFrom = function(node) { this.expectContextual("from") node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() diff --git a/src/babel/generation/generators/modules.js b/src/babel/generation/generators/modules.js index cb7de0c36e..8c606d35b7 100644 --- a/src/babel/generation/generators/modules.js +++ b/src/babel/generation/generators/modules.js @@ -13,6 +13,10 @@ export function ImportDefaultSpecifier(node, print) { print(node.local); } +export function ExportDefaultSpecifier(node, print) { + print(node.exported); +} + export function ExportSpecifier(node, print) { print(node.local); if (node.exported && node.local !== node.exported) { @@ -21,12 +25,9 @@ export function ExportSpecifier(node, print) { } } -export function ExportNamespaceDeclaration(node, print) { - this.push("export "); +export function ExportNamespaceSpecifier(node, print) { + this.push("* as "); print(node.exported); - this.push(" from "); - print(node.source); - this.semicolon(); } export function ExportAllDeclaration(node, print) { @@ -54,16 +55,29 @@ function ExportDeclaration(node, print) { var specifiers = node.specifiers; if (node.declaration) { - print(node.declaration); - if (t.isStatement(node.declaration)) return; + var declar = node.declaration; + print(declar); + if (t.isStatement(declar) || t.isFunction(declar) || t.isClass(declar)) return; } else { - this.push("{"); - if (specifiers.length) { - this.space(); - print.join(specifiers, { separator: ", " }); - this.space(); + var first = specifiers[0]; + var hasSpecial = false; + if (t.isExportDefaultSpecifier(first) || t.isExportNamespaceSpecifier(first)) { + hasSpecial = true; + print(specifiers.shift()); + if (specifiers.length) { + this.push(", "); + } + } + + if (specifiers.length || (!specifiers.length && !hasSpecial)) { + this.push("{"); + if (specifiers.length) { + this.space(); + print.join(specifiers, { separator: ", " }); + this.space(); + } + this.push("}"); } - this.push("}"); if (node.source) { this.push(" from "); @@ -83,25 +97,20 @@ export function ImportDeclaration(node, print) { var specfiers = node.specifiers; if (specfiers && specfiers.length) { - var foundImportSpecifier = false; - - for (var i = 0; i < node.specifiers.length; i++) { - var spec = node.specifiers[i]; - - if (i > 0) { + var first = node.specifiers[0]; + if (t.isImportDefaultSpecifier(first) || t.isImportNamespaceSpecifier(first)) { + print(node.specifiers.shift()); + if (node.specifiers.length) { this.push(", "); } - - if (!t.isImportDefaultSpecifier(spec) && !t.isImportNamespaceSpecifier(spec) && !foundImportSpecifier) { - foundImportSpecifier = true; - this.push("{ "); - } - - print(spec); } - if (foundImportSpecifier) { - this.push(" }"); + if (node.specifiers.length) { + this.push("{"); + this.space() + print.join(node.specifiers, { separator: ", " }); + this.space() + this.push("}"); } this.push(" from "); diff --git a/src/babel/transformation/modules/_default.js b/src/babel/transformation/modules/_default.js index 534af2333d..7d2555275d 100644 --- a/src/babel/transformation/modules/_default.js +++ b/src/babel/transformation/modules/_default.js @@ -62,7 +62,7 @@ var exportsVisitor = traverse.explode({ extend(formatter.localExports, declar.getBindingIdentifiers()); } - if (!t.isExportDefaultDeclaration(node) && !t.isExportNamespaceDeclaration(node)) { + if (!t.isExportDefaultDeclaration(node)) { formatter.hasNonDefaultExports = true; } diff --git a/src/babel/transformation/transformers/es7/export-extensions.js b/src/babel/transformation/transformers/es7/export-extensions.js index 0d6caa3c06..561f3bd485 100644 --- a/src/babel/transformation/transformers/es7/export-extensions.js +++ b/src/babel/transformation/transformers/es7/export-extensions.js @@ -3,23 +3,33 @@ import * as t from "../../../types"; export function check(node) { - return t.isExportNamespaceDeclaration(node) || (t.isExportAllDeclaration(node) && node.exported); + return t.isExportDefaultSpecifier(node) || t.isExportNamespaceSpecifier(node); } -export function ExportNamespaceDeclaration(node, parent, scope) { - var uid = scope.generateUidIdentifier("default"); - return [ - t.importDeclaration([t.importDefaultSpecifier(uid)], node.source), - t.exportDefaultDeclaration(uid) - ]; -} +export function ExportNamedDeclaration(node, parent, scope) { + var nodes = []; -export function ExportAllDeclaration(node, parent, scope) { - if (node.exported) { - var uid = scope.generateUidIdentifier(node.exported.name); - return [ + if (t.isExportNamespaceSpecifier(node.specifiers[0])) { + var specifier = node.specifiers.shift(); + var uid = scope.generateUidIdentifier(specifier.exported.name); + nodes.push( t.importDeclaration([t.importNamespaceSpecifier(uid)], node.source), - t.exportNamedDeclaration(null, [t.exportSpecifier(uid, node.exported)]) - ]; + t.exportNamedDeclaration(null, [t.exportSpecifier(uid, specifier.exported)]) + ); + } else if (t.isExportDefaultSpecifier(node.specifiers[0])) { + var specifier = node.specifiers.shift(); + var uid = scope.generateUidIdentifier(specifier.exported.name); + nodes.push( + t.importDeclaration([t.importSpecifier(uid, specifier.exported)], node.source), + t.exportNamedDeclaration(null, [t.exportSpecifier(uid, specifier.exported)]) + ); } + + if (!nodes.length) return; + + if (node.specifiers.length > 1) { + nodes.push(node); + } + + return nodes; } diff --git a/src/babel/types/alias-keys.json b/src/babel/types/alias-keys.json index 4a36b511f5..9984502ee0 100644 --- a/src/babel/types/alias-keys.json +++ b/src/babel/types/alias-keys.json @@ -15,7 +15,9 @@ "LabeledStatement": ["Statement"], "VariableDeclaration": ["Statement", "Declaration"], - "ExportNamespaceDeclaration": ["Statement", "Declaration", "ModuleDeclaration", "ExportDeclaration"], + "ExportDefaultSpecifier": ["ModuleSpecifier"], + "ExportNamespaceSpecifier": ["ModuleSpecifier"], + "ExportDefaultFromSpecifier": ["ModuleSpecifier"], "ExportAllDeclaration": ["Statement", "Declaration", "ModuleDeclaration", "ExportDeclaration"], "ExportDefaultDeclaration": ["Statement", "Declaration", "ModuleDeclaration", "ExportDeclaration"], "ExportNamedDeclaration": ["Statement", "Declaration", "ModuleDeclaration", "ExportDeclaration"], diff --git a/src/babel/types/visitor-keys.json b/src/babel/types/visitor-keys.json index 96e9396751..9dd063eb18 100644 --- a/src/babel/types/visitor-keys.json +++ b/src/babel/types/visitor-keys.json @@ -69,9 +69,10 @@ "YieldExpression": ["argument"], "ExportAllDeclaration": ["source", "exported"], - "ExportNamespaceDeclaration": ["exported"], "ExportDefaultDeclaration": ["declaration"], "ExportNamedDeclaration": ["declaration", "specifiers", "source"], + "ExportDefaultSpecifier": ["exported"], + "ExportNamespaceSpecifier": ["exported"], "ExportSpecifier": ["local", "exported"], "AnyTypeAnnotation": [], diff --git a/test/acorn/driver.js b/test/acorn/driver.js index ed48ace821..08e368bc0d 100755 --- a/test/acorn/driver.js +++ b/test/acorn/driver.js @@ -33,7 +33,7 @@ else callback("fail", test.code, "Expected error message: " + test.error + "\nGot error message: " + e.message); } else { - callback("error", test.code, e.message || e.toString()); + callback("error", test.code, e.stack || e.toString()); } continue } diff --git a/test/acorn/tests-babel.js b/test/acorn/tests-babel.js index e03f861918..b46ddf9628 100644 --- a/test/acorn/tests-babel.js +++ b/test/acorn/tests-babel.js @@ -2789,18 +2789,89 @@ test('class Foo { @bar static foo = "bar"; }', { // ES7 export extensions - https://github.com/leebyron/ecmascript-more-export-from +test('export foo, { bar } from "bar";', { + type: "Program", + body: [{ + type: "ExportNamedDeclaration", + start: 0, + end: 31, + specifiers: [{ + type: "ExportDefaultSpecifier", + exported: { + type: "Identifier", + name: "foo", + start: 7, + end: 10, + } + }, { + type: "ExportSpecifier", + exported: { + type: "Identifier", + name: "bar" + } + }], + source: { + type: "Literal", + value: "bar", + start: 25, + end: 30 + } + }] +}, { + ecmaVersion: 7, + sourceType: "module", + features: { "es7.exportExtensions": true } +}); + +test('export * as foo, { bar } from "bar";', { + type: "Program", + body: [{ + type: "ExportNamedDeclaration", + start: 0, + end: 36, + specifiers: [{ + type: "ExportNamespaceSpecifier", + exported: { + type: "Identifier", + name: "foo", + start: 12, + end: 15, + } + }, { + type: "ExportSpecifier", + exported: { + type: "Identifier", + name: "bar" + } + }], + source: { + type: "Literal", + value: "bar", + start: 30, + end: 35 + } + }] +}, { + ecmaVersion: 7, + sourceType: "module", + features: { "es7.exportExtensions": true } +}); + test('export foo from "bar";', { type: "Program", body: [{ - type: "ExportNamespaceDeclaration", + type: "ExportNamedDeclaration", start: 0, end: 22, - exported: { - type: "Identifier", - name: "foo", - start: 7, - end: 10, - }, + specifiers: [{ + type: "ExportDefaultSpecifier", + exported: { + type: "Identifier", + name: "foo", + start: 7, + end: 10, + } + }], source: { type: "Literal", value: "bar", @@ -2814,18 +2885,49 @@ test('export foo from "bar";', { features: { "es7.exportExtensions": true } }); +test('export default from "bar";', { + type: "Program", + body: [{ + type: "ExportNamedDeclaration", + start: 0, + end: 26, + specifiers: [{ + type: "ExportDefaultSpecifier", + exported: { + type: "Identifier", + name: "default", + start: 7, + end: 14, + } + }], + source: { + type: "Literal", + value: "bar", + start: 20, + end: 25 + } + }] +}, { + ecmaVersion: 7, + sourceType: "module", + features: { "es7.exportExtensions": true } +}); + test('export * as foo from "bar";', { type: "Program", body: [{ - type: "ExportAllDeclaration", + type: "ExportNamedDeclaration", start: 0, end: 27, - exported: { - type: "Identifier", - name: "foo", - start: 12, - end: 15, - }, + specifiers: [{ + type: "ExportNamespaceSpecifier", + exported: { + type: "Identifier", + name: "foo", + start: 12, + end: 15, + } + }], source: { type: "Literal", value: "bar", diff --git a/test/core/fixtures/generation/types/ExportDefaultDeclaration-ExportSpecifier-ExportNamedDeclaration/actual.js b/test/core/fixtures/generation/types/ExportDefaultDeclaration-ExportSpecifier-ExportNamedDeclaration/actual.js index 608bb1f979..288b335663 100644 --- a/test/core/fixtures/generation/types/ExportDefaultDeclaration-ExportSpecifier-ExportNamedDeclaration/actual.js +++ b/test/core/fixtures/generation/types/ExportDefaultDeclaration-ExportSpecifier-ExportNamedDeclaration/actual.js @@ -9,6 +9,8 @@ export default class Foo {} export * from "foo"; export * as foo from "foo"; export foo from "foo"; +export * as foo, { bar } from "foo"; +export foo, { bar } from "foo"; export { foo } from "foo"; export { foo, bar } from "foo"; export { foo as bar } from "foo"; diff --git a/test/core/fixtures/generation/types/ExportDefaultDeclaration-ExportSpecifier-ExportNamedDeclaration/expected.js b/test/core/fixtures/generation/types/ExportDefaultDeclaration-ExportSpecifier-ExportNamedDeclaration/expected.js index 0af006e319..288b335663 100644 --- a/test/core/fixtures/generation/types/ExportDefaultDeclaration-ExportSpecifier-ExportNamedDeclaration/expected.js +++ b/test/core/fixtures/generation/types/ExportDefaultDeclaration-ExportSpecifier-ExportNamedDeclaration/expected.js @@ -2,13 +2,15 @@ export default 42; export default {}; export default []; export default foo; -export default function () {}; -export default class {}; +export default function () {} +export default class {} export default function foo() {} export default class Foo {} export * from "foo"; export * as foo from "foo"; export foo from "foo"; +export * as foo, { bar } from "foo"; +export foo, { bar } from "foo"; export { foo } from "foo"; export { foo, bar } from "foo"; export { foo as bar } from "foo"; diff --git a/test/core/fixtures/transformation/es7-export-extensions/default-commonjs/expected.js b/test/core/fixtures/transformation/es7-export-extensions/default-commonjs/expected.js index dee58d49c3..6e836ca721 100644 --- a/test/core/fixtures/transformation/es7-export-extensions/default-commonjs/expected.js +++ b/test/core/fixtures/transformation/es7-export-extensions/default-commonjs/expected.js @@ -1,5 +1,9 @@ "use strict"; -var _default = babelHelpers.interopRequire(require("bar")); +Object.defineProperty(exports, "__esModule", { + value: true +}); -module.exports = _default; +var _foo = require("bar").foo; + +exports.foo = _foo; diff --git a/test/core/fixtures/transformation/es7-export-extensions/default-es6/expected.js b/test/core/fixtures/transformation/es7-export-extensions/default-es6/expected.js index 5557329cbb..396e94f2f7 100644 --- a/test/core/fixtures/transformation/es7-export-extensions/default-es6/expected.js +++ b/test/core/fixtures/transformation/es7-export-extensions/default-es6/expected.js @@ -1,4 +1,4 @@ "use strict"; -import _default from "bar"; -export default _default; +import { foo as _foo } from "bar"; +export { _foo as foo };