Skip to content

Commit 26ad6d4

Browse files
GabrielRatenerlydell
authored andcommitted
Selectively ignore CS-only keywords in ES imports and exports (jashkenas#4347)
1 parent 887052d commit 26ad6d4

File tree

4 files changed

+84
-14
lines changed

4 files changed

+84
-14
lines changed

lib/coffee-script/lexer.js

Lines changed: 19 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lexer.coffee

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ exports.Lexer = class Lexer
4545
@seenFor = no # Used to recognize FORIN and FOROF tokens.
4646
@seenImport = no # Used to recognize IMPORT FROM? AS? tokens.
4747
@seenExport = no # Used to recognize EXPORT FROM? AS? tokens.
48+
@exportSpecifierList = no # Used to identify when in an EXPORT {...} FROM? ...
4849

4950
@chunkLine =
5051
opts.line or 0 # The start line for the current @chunk.
@@ -115,10 +116,14 @@ exports.Lexer = class Lexer
115116
if id is 'from' and @tag() is 'YIELD'
116117
@token 'FROM', id
117118
return id.length
118-
if id is 'as' and @seenImport and (@tag() is 'IDENTIFIER' or @value() is '*')
119-
@tokens[@tokens.length - 1][0] = 'IMPORT_ALL' if @value() is '*'
120-
@token 'AS', id
121-
return id.length
119+
if id is 'as' and @seenImport
120+
if @value() is '*'
121+
@tokens[@tokens.length - 1][0] = 'IMPORT_ALL'
122+
else if @value() in COFFEE_KEYWORDS
123+
@tokens[@tokens.length - 1][0] = 'IDENTIFIER'
124+
if @tag() in ['IMPORT_ALL', 'IDENTIFIER']
125+
@token 'AS', id
126+
return id.length
122127
if id is 'as' and @seenExport and @tag() is 'IDENTIFIER'
123128
@token 'AS', id
124129
return id.length
@@ -136,7 +141,8 @@ exports.Lexer = class Lexer
136141
else
137142
'IDENTIFIER'
138143

139-
if tag is 'IDENTIFIER' and (id in JS_KEYWORDS or id in COFFEE_KEYWORDS)
144+
if tag is 'IDENTIFIER' and (id in JS_KEYWORDS or id in COFFEE_KEYWORDS) and
145+
not (@exportSpecifierList and id in COFFEE_KEYWORDS)
140146
tag = id.toUpperCase()
141147
if tag is 'WHEN' and @tag() in LINE_BREAK
142148
tag = 'LEADING_WHEN'
@@ -456,6 +462,11 @@ exports.Lexer = class Lexer
456462
@error message, origin[2] if message
457463
return value.length if skipToken
458464

465+
if value is '{' and prev?[0] is 'EXPORT'
466+
@exportSpecifierList = yes
467+
else if @exportSpecifierList and value is '}'
468+
@exportSpecifierList = no
469+
459470
if value is ';'
460471
@seenFor = @seenImport = @seenExport = no
461472
tag = 'TERMINATOR'

test/error_messages.coffee

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,3 +1154,23 @@ test "imported members cannot be reassigned", ->
11541154
export foo = 'bar'
11551155
^^^
11561156
'''
1157+
1158+
test "CS only keywords can't be used as unaliased names in import lists", ->
1159+
assertErrorFormat """
1160+
import { unless, baz as bar } from 'lib'
1161+
bar.barMethod()
1162+
""", '''
1163+
[stdin]:1:10: error: unexpected unless
1164+
import { unless, baz as bar } from 'lib'
1165+
^^^^^^
1166+
'''
1167+
1168+
test "CS only keywords can't be used as local names in import list aliases", ->
1169+
assertErrorFormat """
1170+
import { bar as unless, baz as bar } from 'lib'
1171+
bar.barMethod()
1172+
""", '''
1173+
[stdin]:1:17: error: unexpected unless
1174+
import { bar as unless, baz as bar } from 'lib'
1175+
^^^^^^
1176+
'''

test/modules.coffee

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,23 @@ test "export as aliases members imported from another module", ->
510510
} from 'lib';"""
511511
eq toJS(input), output
512512

513+
test "export list can contain CS only keywords", ->
514+
input = "export { unless } from 'lib'"
515+
output = """
516+
export {
517+
unless
518+
} from 'lib';"""
519+
eq toJS(input), output
520+
521+
test "export list can contain CS only keywords when aliasing", ->
522+
input = "export { when as bar, baz as unless } from 'lib'"
523+
output = """
524+
export {
525+
when as bar,
526+
baz as unless
527+
} from 'lib';"""
528+
eq toJS(input), output
529+
513530

514531
# Edge cases
515532

@@ -608,6 +625,18 @@ test "`as` can be used as an alias name", ->
608625
} from 'lib';"""
609626
eq toJS(input), output
610627

628+
test "CS only keywords can be used as imported names in import lists", ->
629+
input = """
630+
import { unless as bar } from 'lib'
631+
bar.barMethod()"""
632+
output = """
633+
import {
634+
unless as bar
635+
} from 'lib';
636+
637+
bar.barMethod();"""
638+
eq toJS(input), output
639+
611640
test "`*` can be used in an expression on the same line as an export keyword", ->
612641
input = "export foo = (x) -> x * x"
613642
output = """

0 commit comments

Comments
 (0)