From 593a4cb16d0e2180bbe50b5162a60162fbb00fc5 Mon Sep 17 00:00:00 2001 From: Kieran Huggins Date: Fri, 18 Dec 2015 01:59:30 -0500 Subject: [PATCH] consider es6 module syntax to be plain JS [fixes #3162] --- lib/coffee-script/lexer.js | 15 ++++++++-- src/lexer.coffee | 9 ++++++ test/javascript_literals.coffee | 49 +++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/lib/coffee-script/lexer.js b/lib/coffee-script/lexer.js index ed8b8b3177..557c46af54 100644 --- a/lib/coffee-script/lexer.js +++ b/lib/coffee-script/lexer.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.10.0 (function() { - var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError, + var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MODULETOKEN, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; ref = require('./rewriter'), Rewriter = ref.Rewriter, INVERSES = ref.INVERSES; @@ -29,7 +29,7 @@ code = this.clean(code); i = 0; while (this.chunk = code.slice(i)) { - consumed = this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken(); + consumed = this.moduleToken() || this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken(); ref2 = this.getLineAndColumnFromChunk(consumed), this.chunkLine = ref2[0], this.chunkColumn = ref2[1]; i += consumed; if (opts.untilBalanced && this.ends.length === 0) { @@ -303,6 +303,15 @@ return script.length; }; + Lexer.prototype.moduleToken = function() { + var match, script; + if (!(match = MODULETOKEN.exec(this.chunk))) { + return 0; + } + this.token('JS', (script = match[0]), 0, script.length); + return script.length; + }; + Lexer.prototype.regexToken = function() { var body, closed, end, flags, index, match, origin, prev, ref2, ref3, ref4, regex, tokens; switch (false) { @@ -938,6 +947,8 @@ JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/; + MODULETOKEN = /^(import|export)\s+[^#\\\n]*/; + STRING_START = /^(?:'''|"""|'|")/; STRING_SINGLE = /^(?:[^\\']|\\[\s\S])*/; diff --git a/src/lexer.coffee b/src/lexer.coffee index e22b69135a..1a14e21680 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -56,6 +56,7 @@ exports.Lexer = class Lexer i = 0 while @chunk = code[i..] consumed = \ + @moduleToken() or @identifierToken() or @commentToken() or @whitespaceToken() or @@ -255,6 +256,12 @@ exports.Lexer = class Lexer @token 'JS', (script = match[0])[1...-1], 0, script.length script.length + # Matches JavaScript interpolated directly into the source via module syntax. + moduleToken: -> + return 0 unless match = MODULETOKEN.exec @chunk + @token 'JS', (script = match[0]), 0, script.length + script.length + # Matches regular expression literals, as well as multiline extended ones. # Lexing regular expressions is difficult to distinguish from division, so we # borrow some basic heuristics from JavaScript and Ruby. @@ -824,6 +831,8 @@ MULTI_DENT = /^(?:\n[^\n\S]*)+/ JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/ +MODULETOKEN = /^(import|export)\s+[^#\\\n]*/ + # String-matching-regexes. STRING_START = /^(?:'''|"""|'|")/ diff --git a/test/javascript_literals.coffee b/test/javascript_literals.coffee index 91a9efddeb..d3392ab5d1 100644 --- a/test/javascript_literals.coffee +++ b/test/javascript_literals.coffee @@ -8,3 +8,52 @@ eq '\\`', ` // Inline JS "\\\`" ` + +toJS = (str)-> + CoffeeScript.compile str, bare: true + .replace /^\s+|\s+$/g, "" + +test "regular JS literal import statement", -> + input = '`import { member as alias } from "module-name"`' + output = 'import { member as alias } from "module-name";' + eq toJS(input), output + +test "module import test, syntax #1", -> + input = "import foo from 'lib'" + output = "import foo from 'lib';" + eq toJS(input), output + +test "module import test, syntax #2", -> + input = "import { foo } from 'lib'" + output = "import { foo } from 'lib';" + eq toJS(input), output + +test "module import test, syntax #3", -> + input = "import { default as foo } from 'lib'" + output = "import { default as foo } from 'lib';" + eq toJS(input), output + +test "module import test, syntax #4", -> + input = "import { square, diag } from 'lib'" + output = "import { square, diag } from 'lib';" + eq toJS(input), output + +test "module import test, syntax #5", -> + input = "import { foo } from 'lib' # with a comment" + output = "import { foo } from 'lib' ;" + eq toJS(input), output + +test "module export test, syntax #1", -> + input = "export default mixin" + output = "export default mixin;" + eq toJS(input), output + +test "module export test, syntax #2", -> + input = "export { D as default }" + output = "export { D as default };" + eq toJS(input), output + +test "module export test, syntax #3", -> + input = "export const sqrt = Math.sqrt" + output = "export const sqrt = Math.sqrt;" + eq toJS(input), output