diff --git a/src/loose/statement.js b/src/loose/statement.js index 192df43e0..041f22bb1 100644 --- a/src/loose/statement.js +++ b/src/loose/statement.js @@ -168,7 +168,7 @@ lp.parseStatement = function() { return this.parseImport() case tt._export: - return this.parseExport() + return this.parseExport(node) default: if (this.toks.isAsyncFunction()) { @@ -334,14 +334,51 @@ lp.parseFunction = function(node, isStatement, isAsync) { return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression") } -lp.parseExport = function() { - let node = this.startNode() +lp.parseExport = function(node) { this.next() - if (this.eat(tt.star)) { - node.source = this.eatContextual("from") ? this.parseExprAtom() : this.dummyString() - return this.finishNode(node, "ExportAllDeclaration") - } - if (this.eat(tt._default)) { + if (this.tok.type === tt.star) { + const specifier = this.startNode() + this.next() + if (this.options.exportExtensions && + this.eatContextual("as")) { + // export * as ns from '...' + specifier.exported = this.parseIdent() + node.specifiers = [ + this.finishNode(specifier, "ExportNamespaceSpecifier") + ] + this.parseExportSpecifiersMaybe(node) + this.parseExportFrom(node) + } else { + // export * from '...' + this.parseExportFrom(node) + return this.finishNode(node, "ExportAllDeclaration") + } + } else if (this.options.exportExtensions && + this.isExportDefaultSpecifier()) { + // export def from '...' + const specifier = this.startNode() + specifier.exported = this.parseIdent(true) + node.specifiers = [ + this.finishNode(specifier, "ExportDefaultSpecifier") + ] + if (this.tok.type === tt.comma && + this.lookAhead(1).type === tt.star) { + // export def, * as ns from '...' + this.expect(tt.comma) + const specifier = this.startNode() + this.expect(tt.star) + specifier.exported = this.eatContextual("as") + ? this.parseIdent() + : this.dummyIdent() + node.specifiers.push( + this.finishNode(specifier, "ExportNamespaceSpecifier") + ) + } else { + // export def, { x, y as z } from '...' + this.parseExportSpecifiersMaybe(node) + } + this.parseExportFrom(node) + } else if (this.eat(tt._default)) { // export default (function foo() {}) // This is FunctionExpression. let isAsync if (this.tok.type === tt._function || (isAsync = this.toks.isAsyncFunction())) { @@ -356,8 +393,9 @@ lp.parseExport = function() { this.semicolon() } return this.finishNode(node, "ExportDefaultDeclaration") - } - if (this.tok.type.keyword || this.toks.isLet() || this.toks.isAsyncFunction()) { + } else if (this.tok.type.keyword || + this.toks.isLet() || + this.toks.isAsyncFunction()) { node.declaration = this.parseStatement() node.specifiers = [] node.source = null @@ -370,6 +408,31 @@ lp.parseExport = function() { return this.finishNode(node, "ExportNamedDeclaration") } +lp.isExportDefaultSpecifier = function() { + if (this.tok.type !== tt.name) { + return false + } + + const lookAhead = this.lookAhead(1) + return lookAhead.type === tt.comma || + (lookAhead.type === tt.name && + lookAhead.value === "from") +} + +lp.parseExportSpecifiersMaybe = function(node) { + if (this.eat(tt.comma)) { + node.specifiers.push.apply( + node.specifiers, + this.parseExportSpecifierList() + ) + } +} + +lp.parseExportFrom = function(node) { + const hasSource = this.eatContextual("from") && this.tok.type === tt.string + node.source = hasSource ? this.parseExprAtom() : this.dummyString() +} + lp.parseImport = function() { let node = this.startNode() this.next() diff --git a/src/options.js b/src/options.js index 9dda44ae8..70ae7ee2b 100644 --- a/src/options.js +++ b/src/options.js @@ -37,6 +37,9 @@ export const defaultOptions = { // When enabled, hashbang directive in the beginning of file // is allowed and treated as a line comment. allowHashBang: false, + // When true, `export * as ns from "..."` and `export def from "..."` + // export extensions will be enabled. + exportExtensions: false, // When `locations` is on, `loc` properties holding objects with // `start` and `end` properties in `{line, column}` form (with // line being 1-based and column 0-based) will be attached to the diff --git a/src/scope.js b/src/scope.js index 2ec044899..68d7d340c 100644 --- a/src/scope.js +++ b/src/scope.js @@ -4,7 +4,7 @@ import {has} from "./util" const pp = Parser.prototype // Object.assign polyfill -const assign = Object.assign || function(target, ...sources) { +export const assign = Object.assign || function(target, ...sources) { for (let i = 0; i < sources.length; i++) { const source = sources[i] for (const key in source) { diff --git a/src/state.js b/src/state.js index 5d9ae7501..a740956e5 100644 --- a/src/state.js +++ b/src/state.js @@ -72,6 +72,9 @@ export class Parser { this.inModule = options.sourceType === "module" this.strict = this.inModule || this.strictDirective(this.pos) + // Temporarily true while Parser#lookAhead calls this.next(). + this.isLookAhead = false + // Used to signify the start of a potential arrow function this.potentialArrowAt = -1 diff --git a/src/statement.js b/src/statement.js index eb2f18e8b..ad4ad8d5c 100644 --- a/src/statement.js +++ b/src/statement.js @@ -590,14 +590,49 @@ pp.parseClassSuper = function(node) { pp.parseExport = function(node, exports) { this.next() - // export * from '...' - if (this.eat(tt.star)) { - this.expectContextual("from") - node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() - this.semicolon() - return this.finishNode(node, "ExportAllDeclaration") - } - if (this.eat(tt._default)) { // export default ... + if (this.type === tt.star) { + const specifier = this.startNode() + this.next() + if (this.options.exportExtensions && + this.eatContextual("as")) { + // export * as ns from '...' + specifier.exported = this.parseIdent(true) + node.specifiers = [ + this.finishNode(specifier, "ExportNamespaceSpecifier") + ] + this.parseExportSpecifiersMaybe(node) + this.parseExportFromWithCheck(node, exports, true) + } else { + // export * from '...' + this.parseExportFromWithCheck(node, exports, true) + return this.finishNode(node, "ExportAllDeclaration") + } + } else if (this.options.exportExtensions && + this.isExportDefaultSpecifier()) { + // export def from '...' + const specifier = this.startNode() + specifier.exported = this.parseIdent(true) + node.specifiers = [ + this.finishNode(specifier, "ExportDefaultSpecifier") + ] + if (this.type === tt.comma && + this.lookAhead(1).type === tt.star) { + // export def, * as ns from '...' + this.expect(tt.comma) + const specifier = this.startNode() + this.expect(tt.star) + this.expectContextual("as") + specifier.exported = this.parseIdent(true) + node.specifiers.push( + this.finishNode(specifier, "ExportNamespaceSpecifier") + ) + } else { + // export def, { x, y as z } from '...' + this.parseExportSpecifiersMaybe(node) + } + this.parseExportFromWithCheck(node, exports, true) + } else if (this.eat(tt._default)) { + // export default ... this.checkExport(exports, "default", this.lastTokStart) let isAsync if (this.type === tt._function || (isAsync = this.isAsyncFunction())) { @@ -613,9 +648,8 @@ pp.parseExport = function(node, exports) { this.semicolon() } return this.finishNode(node, "ExportDefaultDeclaration") - } - // export var|const|let|function|class ... - if (this.shouldParseExportStatement()) { + } else if (this.shouldParseExportDeclaration()) { + // export var|const|let|function|class ... node.declaration = this.parseStatement(true) if (node.declaration.type === "VariableDeclaration") this.checkVariableExport(exports, node.declaration.declarations) @@ -623,24 +657,72 @@ pp.parseExport = function(node, exports) { this.checkExport(exports, node.declaration.id.name, node.declaration.id.start) node.specifiers = [] node.source = null - } else { // export { x, y as z } [from '...'] + } else { + // export { x, y as z } [from '...'] node.declaration = null node.specifiers = this.parseExportSpecifiers(exports) - if (this.eatContextual("from")) { - node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() - } else { + this.parseExportFrom(node, false) + } + return this.finishNode(node, "ExportNamedDeclaration") +} + +pp.isExportDefaultSpecifier = function() { + if (this.type !== tt.name) { + return false + } + + const lookAhead = this.lookAhead(1) + return lookAhead.type === tt.comma || + (lookAhead.type === tt.name && + lookAhead.value === "from") +} + +pp.parseExportSpecifiersMaybe = function(node) { + if (this.eat(tt.comma)) { + node.specifiers.push.apply( + node.specifiers, + this.parseExportSpecifiers() + ) + } +} + +pp.parseExportFromWithCheck = function(node, exports, expect) { + this.parseExportFrom(node, expect) + + if (node.specifiers) { + for (let i = 0; i < node.specifiers.length; i++) { + const s = node.specifiers[i] + const exported = s.exported + this.checkExport(exports, exported.name, exported.start) + } + } +} + +pp.parseExportFrom = function(node, expect) { + if (this.eatContextual("from")) { + node.source = this.type === tt.string + ? this.parseExprAtom() + : this.unexpected() + } else { + if (node.specifiers) { // check for keywords used as local names for (let i = 0; i < node.specifiers.length; i++) { - if (this.keywords.test(node.specifiers[i].local.name) || this.reservedWords.test(node.specifiers[i].local.name)) { - this.unexpected(node.specifiers[i].local.start) + const local = node.specifiers[i].local + if (local && (this.keywords.test(local.name) || + this.reservedWords.test(local.name))) { + this.unexpected(local.start) } } + } + if (expect) { + this.unexpected() + } else { node.source = null } - this.semicolon() } - return this.finishNode(node, "ExportNamedDeclaration") + + this.semicolon() } pp.checkExport = function(exports, name, pos) { @@ -674,7 +756,7 @@ pp.checkVariableExport = function(exports, decls) { this.checkPatternExport(exports, decls[i].id) } -pp.shouldParseExportStatement = function() { +pp.shouldParseExportDeclaration = function() { return this.type.keyword === "var" || this.type.keyword === "const" || this.type.keyword === "class" || diff --git a/src/tokenize.js b/src/tokenize.js index 917a013b8..f2679d437 100644 --- a/src/tokenize.js +++ b/src/tokenize.js @@ -3,6 +3,8 @@ import {types as tt, keywords as keywordTypes} from "./tokentype" import {Parser} from "./state" import {SourceLocation} from "./locutil" import {lineBreak, lineBreakG, isNewLine, nonASCIIwhitespace} from "./whitespace" +import {assign} from "./scope" +import {create} from "./walk/index" // Object type used to represent tokens. Note that normally, tokens // simply exist as properties on the parser object. This is only @@ -31,8 +33,9 @@ const isRhino = typeof Packages == "object" && Object.prototype.toString.call(Pa // Move to the next token pp.next = function() { - if (this.options.onToken) + if (!this.isLookAhead && this.options.onToken) { this.options.onToken(new Token(this)) + } this.lastTokEnd = this.end this.lastTokStart = this.start @@ -67,6 +70,20 @@ pp.curContext = function() { return this.context[this.context.length - 1] } +// Return a snapshot of the parser after calling this.nextToken(), without +// permanently updating the parser's state. + +pp.lookAhead = function(n = 1) { + const old = assign(create(null), this) + const oldIsLookAhead = this.isLookAhead + this.isLookAhead = true + while (n-- > 0) this.nextToken() + this.isLookAhead = oldIsLookAhead + const copy = assign(create(null), this) + assign(this, old) + return copy +} + // Read a single token, updating the parser object's token-related // properties. @@ -111,9 +128,10 @@ pp.skipBlockComment = function() { this.lineStart = match.index + match[0].length } } - if (this.options.onComment) + if (!this.isLookAhead && this.options.onComment) { this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos, startLoc, this.curPosition()) + } } pp.skipLineComment = function(startSkip) { @@ -124,9 +142,10 @@ pp.skipLineComment = function(startSkip) { ++this.pos ch = this.input.charCodeAt(this.pos) } - if (this.options.onComment) + if (!this.isLookAhead && this.options.onComment) { this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos, startLoc, this.curPosition()) + } } // Called at the start of the parse and after every token. Skips diff --git a/src/walk/index.js b/src/walk/index.js index e1c6ad409..8b0c698d0 100644 --- a/src/walk/index.js +++ b/src/walk/index.js @@ -140,7 +140,7 @@ export function findNodeBefore(node, pos, test, base, state) { } // Fallback to an Object.create polyfill for older environments. -const create = Object.create || function(proto) { +export const create = Object.create || function(proto) { function Ctor() {} Ctor.prototype = proto return new Ctor diff --git a/test/tests-harmony.js b/test/tests-harmony.js index 9bcd8b271..876e29e0c 100644 --- a/test/tests-harmony.js +++ b/test/tests-harmony.js @@ -4580,6 +4580,723 @@ test("export { default } from \"other\"", { locations: true }); +test('export * as ns from "module"', { + type: "Program", + start: 0, + end: 28, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 28} + }, + range: [0, 28], + body: [{ + type: "ExportNamedDeclaration", + start: 0, + end: 28, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 28} + }, + range: [0, 28], + specifiers: [{ + type: "ExportNamespaceSpecifier", + start: 7, + end: 14, + loc: { + start: {line: 1, column: 7}, + end: {line: 1, column: 14} + }, + range: [7, 14], + exported: { + type: "Identifier", + start: 12, + end: 14, + loc: { + start: {line: 1, column: 12}, + end: {line: 1, column: 14} + }, + range: [12, 14], + name: "ns" + } + }], + source: { + type: "Literal", + start: 20, + end: 28, + loc: { + start: {line: 1, column: 20}, + end: {line: 1, column: 28} + }, + range: [20, 28], + value: "module", + raw: '"module"' + } + }] +}, { + ecmaVersion: 6, + sourceType: "module", + exportExtensions: true, + ranges: true, + locations: true +}); + +test('export def from "module"', { + type: "Program", + start: 0, + end: 24, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 24} + }, + range: [0, 24], + body: [{ + type: "ExportNamedDeclaration", + start: 0, + end: 24, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 24} + }, + range: [0, 24], + specifiers: [{ + type: "ExportDefaultSpecifier", + start: 7, + end: 10, + loc: { + start: {line: 1, column: 7}, + end: {line: 1, column: 10} + }, + range: [7, 10], + exported: { + type: "Identifier", + start: 7, + end: 10, + loc: { + start: {line: 1, column: 7}, + end: {line: 1, column: 10} + }, + range: [7, 10], + name: "def" + } + }], + source: { + type: "Literal", + start: 16, + end: 24, + loc: { + start: {line: 1, column: 16}, + end: {line: 1, column: 24} + }, + range: [16, 24], + value: "module", + raw: '"module"' + } + }] +}, { + ecmaVersion: 6, + sourceType: "module", + exportExtensions: true, + ranges: true, + locations: true +}); + +test('export def, * as ns from "module"', { + type: "Program", + start: 0, + end: 33, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 33} + }, + range: [0, 33], + body: [{ + type: "ExportNamedDeclaration", + start: 0, + end: 33, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 33} + }, + range: [0, 33], + specifiers: [{ + type: "ExportDefaultSpecifier", + start: 7, + end: 10, + loc: { + start: {line: 1, column: 7}, + end: {line: 1, column: 10} + }, + range: [7, 10], + exported: { + type: "Identifier", + start: 7, + end: 10, + loc: { + start: {line: 1, column: 7}, + end: {line: 1, column: 10} + }, + range: [7, 10], + name: "def" + } + }, { + type: "ExportNamespaceSpecifier", + start: 12, + end: 19, + loc: { + start: { column: 12}, + end: {line: 1, column: 19} + }, + range: [12, 19], + exported: { + type: "Identifier", + start: 17, + end: 19, + loc: { + start: {line: 1, column: 17}, + end: {line: 1, column: 19} + }, + range: [17, 19], + name: "ns" + } + }], + source: { + type: "Literal", + start: 25, + end: 33, + loc: { + start: {line: 1, column: 25}, + end: {line: 1, column: 33} + }, + range: [25, 33], + value: "module", + raw: '"module"' + } + }] +}, { + ecmaVersion: 6, + sourceType: "module", + exportExtensions: true, + ranges: true, + locations: true +}); + +test('export def, { a, b as c } from "module"', { + type: "Program", + start: 0, + end: 39, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 39} + }, + range: [0, 39], + body: [{ + type: "ExportNamedDeclaration", + start: 0, + end: 39, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 39} + }, + range: [0, 39], + specifiers: [{ + type: "ExportDefaultSpecifier", + start: 7, + end: 10, + loc: { + start: {line: 1, column: 7}, + end: {line: 1, column: 10} + }, + range: [7, 10], + exported: { + type: "Identifier", + start: 7, + end: 10, + loc: { + start: {line: 1, column: 7}, + end: {line: 1, column: 10} + }, + range: [7, 10], + name: "def" + } + }, { + type: "ExportSpecifier", + start: 14, + end: 15, + loc: { + start: {line: 1, column: 14}, + end: {line: 1, column: 15} + }, + range: [14, 15], + local: { + type: "Identifier", + start: 14, + end: 15, + loc: { + start: {line: 1, column: 14}, + end: {line: 1, column: 15} + }, + range: [14, 15], + name: "a" + }, + exported: { + type: "Identifier", + start: 14, + end: 15, + loc: { + start: {line: 1, column: 14}, + end: {line: 1, column: 15} + }, + range: [14, 15], + name: "a" + } + }, { + type: "ExportSpecifier", + start: 17, + end: 23, + loc: { + start: {line: 1, column: 17}, + end: {line: 1, column: 23} + }, + range: [17, 23], + local: { + type: "Identifier", + start: 17, + end: 18, + loc: { + start: {line: 1, column: 17}, + end: {line: 1, column: 18} + }, + range: [17, 18], + name: "b" + }, + exported: { + type: "Identifier", + start: 22, + end: 23, + loc: { + start: {line: 1, column: 22}, + end: {line: 1, column: 23} + }, + range: [22, 23], + name: "c" + } + }], + source: { + type: "Literal", + start: 31, + end: 39, + loc: { + start: {line: 1, column: 31}, + end: {line: 1, column: 39} + }, + range: [31, 39], + value: "module", + raw: '"module"' + } + }] +}, { + ecmaVersion: 6, + sourceType: "module", + exportExtensions: true, + ranges: true, + locations: true +}); + +test('export * as ns, { a, b as c } from "module"', { + type: "Program", + start: 0, + end: 43, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 43} + }, + range: [0, 43], + body: [{ + type: "ExportNamedDeclaration", + start: 0, + end: 43, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 43} + }, + range: [0, 43], + specifiers: [{ + type: "ExportNamespaceSpecifier", + start: 7, + end: 14, + loc: { + start: {line: 1, column: 7}, + end: {line: 1, column: 14} + }, + range: [7, 14], + exported: { + type: "Identifier", + start: 12, + end: 14, + loc: { + start: {line: 1, column: 12}, + end: {line: 1, column: 14} + }, + range: [12, 14], + name: "ns" + } + }, { + type: "ExportSpecifier", + start: 18, + end: 19, + loc: { + start: {line: 1, column: 18}, + end: {line: 1, column: 19} + }, + range: [18, 19], + local: { + type: "Identifier", + start: 18, + end: 19, + loc: { + start: {line: 1, column: 18}, + end: {line: 1, column: 19} + }, + range: [18, 19], + name: "a" + }, + exported: { + type: "Identifier", + start: 18, + end: 19, + loc: { + start: {line: 1, column: 18}, + end: {line: 1, column: 19} + }, + range: [18, 19], + name: "a" + } + }, { + type: "ExportSpecifier", + start: 21, + end: 27, + loc: { + start: {line: 1, column: 21}, + end: {line: 1, column: 27} + }, + range: [21, 27], + local: { + type: "Identifier", + start: 21, + end: 22, + loc: { + start: {line: 1, column: 21}, + end: {line: 1, column: 22} + }, + range: [21, 22], + name: "b" + }, + exported: { + type: "Identifier", + start: 26, + end: 27, + loc: { + start: {line: 1, column: 26}, + end: {line: 1, column: 27} + }, + range: [26, 27], + name: "c" + } + }], + source: { + type: "Literal", + start: 35, + end: 43, + loc: { + start: {line: 1, column: 35}, + end: {line: 1, column: 43} + }, + range: [35, 43], + value: "module", + raw: '"module"' + } + }] +}, { + ecmaVersion: 6, + sourceType: "module", + exportExtensions: true, + ranges: true, + locations: true +}); + +test('export * as default from "module"', { + type: "Program", + start: 0, + end: 33, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 33} + }, + range: [0, 33], + body: [{ + type: "ExportNamedDeclaration", + start: 0, + end: 33, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 33} + }, + range: [0, 33], + specifiers: [{ + type: "ExportNamespaceSpecifier", + start: 7, + end: 19, + loc: { + start: {line: 1, column: 7}, + end: {line: 1, column: 19} + }, + range: [7, 19], + exported: { + type: "Identifier", + start: 12, + end: 19, + loc: { + start: {line: 1, column: 12}, + end: {line: 1, column: 19} + }, + range: [12, 19], + name: "default" + } + }], + source: { + type: "Literal", + start: 25, + end: 33, + loc: { + start: {line: 1, column: 25}, + end: {line: 1, column: 33} + }, + range: [25, 33], + value: "module", + raw: '"module"' + } + }] +}, { + ecmaVersion: 6, + sourceType: "module", + exportExtensions: true, + ranges: true, + locations: true +}); + +test('export def, * as default from "module"', { + type: "Program", + start: 0, + end: 38, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 38} + }, + range: [0, 38], + body: [{ + type: "ExportNamedDeclaration", + start: 0, + end: 38, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 38} + }, + range: [0, 38], + specifiers: [{ + type: "ExportDefaultSpecifier", + start: 7, + end: 10, + loc: { + start: {line: 1, column: 7}, + end: {line: 1, column: 10} + }, + range: [7, 10], + exported: { + type: "Identifier", + start: 7, + end: 10, + loc: { + start: {line: 1, column: 7}, + end: {line: 1, column: 10} + }, + range: [7, 10], + name: "def" + } + }, { + type: "ExportNamespaceSpecifier", + start: 12, + end: 24, + loc: { + start: {line: 1, column: 12}, + end: {line: 1, column: 24} + }, + range: [12, 24], + exported: { + type: "Identifier", + start: 17, + end: 24, + loc: { + start: {line: 1, column: 17}, + end: {line: 1, column: 24} + }, + range: [17, 24], + name: "default" + } + }], + source: { + type: "Literal", + start: 30, + end: 38, + loc: { + start: {line: 1, column: 30}, + end: {line: 1, column: 38} + }, + range: [30, 38], + value: "module", + raw: '"module"' + } + }] +}, { + ecmaVersion: 6, + sourceType: "module", + exportExtensions: true, + ranges: true, + locations: true +}); + +test('export { default, a, b as c } from "module"', { + type: "Program", + start: 0, + end: 43, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 43} + }, + range: [0, 43], + body: [{ + type: "ExportNamedDeclaration", + start: 0, + end: 43, + loc: { + start: {line: 1, column: 0}, + end: {line: 1, column: 43} + }, + range: [0, 43], + declaration: null, + specifiers: [{ + type: "ExportSpecifier", + start: 9, + end: 16, + loc: { + start: {line: 1, column: 9}, + end: {line: 1, column: 16} + }, + range: [9, 16], + local: { + type: "Identifier", + start: 9, + end: 16, + loc: { + start: {line: 1, column: 9}, + end: {line: 1, column: 16} + }, + range: [9, 16], + name: "default" + }, + exported: { + type: "Identifier", + start: 9, + end: 16, + loc: { + start: {line: 1, column: 9}, + end: {line: 1, column: 16} + }, + range: [9, 16], + name: "default" + } + }, { + type: "ExportSpecifier", + start: 18, + end: 19, + loc: { + start: {line: 1, column: 18}, + end: {line: 1, column: 19} + }, + range: [18, 19], + local: { + type: "Identifier", + start: 18, + end: 19, + loc: { + start: {line: 1, column: 18}, + end: {line: 1, column: 19} + }, + range: [18, 19], + name: "a" + }, + exported: { + type: "Identifier", + start: 18, + end: 19, + loc: { + start: {line: 1, column: 18}, + end: {line: 1, column: 19} + }, + range: [18, 19], + name: "a" + } + }, { + type: "ExportSpecifier", + start: 21, + end: 27, + loc: { + start: {line: 1, column: 21}, + end: {line: 1, column: 27} + }, + range: [21, 27], + local: { + type: "Identifier", + start: 21, + end: 22, + loc: { + start: {line: 1, column: 21}, + end: {line: 1, column: 22} + }, + range: [21, 22], + name: "b" + }, + exported: { + type: "Identifier", + start: 26, + end: 27, + loc: { + start: {line: 1, column: 26}, + end: {line: 1, column: 27} + }, + range: [26, 27], + name: "c" + } + }], + source: { + type: "Literal", + start: 35, + end: 43, + loc: { + start: {line: 1, column: 35}, + end: {line: 1, column: 43} + }, + range: [35, 43], + value: "module", + raw: '"module"' + } + }] +}, { + ecmaVersion: 6, + sourceType: "module", + ranges: true, + locations: true +}); + testFail("export { default }", "Unexpected token (1:9)", {ecmaVersion: 6, sourceType: "module" }); testFail("export { if }", "Unexpected token (1:9)", {ecmaVersion: 6, sourceType: "module" }); testFail("export { default as foo }", "Unexpected token (1:9)", {ecmaVersion: 6, sourceType: "module" });