Skip to content

Fix #4491: import- and export-specific lexing should stop #4492

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions lib/coffee-script/lexer.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 10 additions & 3 deletions src/lexer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ exports.Lexer = class Lexer
@seenFor = no # Used to recognize FORIN, FOROF and FORFROM tokens.
@seenImport = no # Used to recognize IMPORT FROM? AS? tokens.
@seenExport = no # Used to recognize EXPORT FROM? AS? tokens.
@importSpecifierList = no # Used to identify when in an IMPORT {...} FROM? ...
@exportSpecifierList = no # Used to identify when in an EXPORT {...} FROM? ...

@chunkLine =
Expand Down Expand Up @@ -365,6 +366,8 @@ exports.Lexer = class Lexer
indent = match[0]

@seenFor = no
@seenImport = no unless @importSpecifierList
@seenExport = no unless @exportSpecifierList

size = indent.length - 1 - indent.lastIndexOf '\n'
noNewlines = @unfinished()
Expand Down Expand Up @@ -473,7 +476,11 @@ exports.Lexer = class Lexer
@error message, origin[2] if message
return value.length if skipToken

if value is '{' and prev?[0] is 'EXPORT'
if value is '{' and @seenImport
@importSpecifierList = yes
else if @importSpecifierList and value is '}'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't handle nested objects, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vendethiel right, I didn't see any cases in the documentation or tests where an import could contain nested-object syntax?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vendethiel the “destructuring” in ES2015 import statements is just a similar-looking syntax:

import { a: b } from 'lib'
repl: ES2015 named imports do not destructure. Use another statement for destructuring after the import. (1:12)
> 1 | import { a: b } from 'lib'
    |             ^

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, thanks, TIL!

@importSpecifierList = no
else if value is '{' and prev?[0] is 'EXPORT'
@exportSpecifierList = yes
else if @exportSpecifierList and value is '}'
@exportSpecifierList = no
Expand Down Expand Up @@ -763,12 +770,12 @@ exports.Lexer = class Lexer

# Validates escapes in strings and regexes.
validateEscapes: (str, options = {}) ->
invalid_escape_regex =
invalidEscapeRegex =
if options.isRegex
REGEX_INVALID_ESCAPE
else
STRING_INVALID_ESCAPE
match = invalid_escape_regex.exec str
match = invalidEscapeRegex.exec str
return unless match
[[], before, octal, hex, unicode] = match
message =
Expand Down
107 changes: 107 additions & 0 deletions test/modules.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -773,3 +773,110 @@ test "#4451: `default` in an export statement is only treated as a keyword when
"default": 1
};
"""
eq toJS(input), output

test "#4491: import- and export-specific lexing should stop after import/export statement", ->
input = """
import {
foo,
bar as baz
} from 'lib'

foo as
3 * as 4
from 'foo'
"""
output = """
import {
foo,
bar as baz
} from 'lib';

foo(as);

3 * as(4);

from('foo');
"""
eq toJS(input), output

input = """
import { foo, bar as baz } from 'lib'

foo as
3 * as 4
from 'foo'
"""
output = """
import {
foo,
bar as baz
} from 'lib';

foo(as);

3 * as(4);

from('foo');
"""
eq toJS(input), output

input = """
import * as lib from 'lib'

foo as
3 * as 4
from 'foo'
"""
output = """
import * as lib from 'lib';

foo(as);

3 * as(4);

from('foo');
"""
eq toJS(input), output

input = """
export {
foo,
bar
}

foo as
3 * as 4
from 'foo'
"""
output = """
export {
foo,
bar
};

foo(as);

3 * as(4);

from('foo');
"""
eq toJS(input), output

input = """
export * from 'lib'

foo as
3 * as 4
from 'foo'
"""
output = """
export * from 'lib';

foo(as);

3 * as(4);

from('foo');
"""
eq toJS(input), output