jashkenas--coffeescript/test/error_messages.coffee

1975 lines
46 KiB
CoffeeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Error Formatting
# ----------------
# Ensure that errors of different kinds (lexer, parser and compiler) are shown
# in a consistent way.
errCallback = (expectedErrorFormat) -> (err) ->
err.colorful = no
eq expectedErrorFormat, "#{err}"
yes
assertErrorFormat = (code, expectedErrorFormat) ->
throws (-> CoffeeScript.run code), errCallback(expectedErrorFormat)
assertErrorFormatAst = (code, expectedErrorFormat) ->
assertErrorFormat code, expectedErrorFormat
throws (-> CoffeeScript.compile code, ast: yes), errCallback(expectedErrorFormat)
test "lexer errors formatting", ->
assertErrorFormat '''
normalObject = {}
insideOutObject = }{
''',
'''
[stdin]:2:19: error: unmatched }
insideOutObject = }{
^
'''
test "parser error formatting", ->
assertErrorFormat '''
foo in bar or in baz
''',
'''
[stdin]:1:15: error: unexpected in
foo in bar or in baz
^^
'''
test "compiler error formatting", ->
assertErrorFormat '''
evil = (foo, eval, bar) ->
''',
'''
[stdin]:1:14: error: 'eval' can't be assigned
evil = (foo, eval, bar) ->
^^^^
'''
if require?
os = require 'os'
fs = require 'fs'
path = require 'path'
test "patchStackTrace line patching", ->
err = new Error 'error'
ok err.stack.match /test[\/\\]error_messages\.coffee:\d+:\d+\b/
test "patchStackTrace stack prelude consistent with V8", ->
err = new Error
ok err.stack.match /^Error\n/ # Notice no colon when no message.
err = new Error 'error'
ok err.stack.match /^Error: error\n/
test "#2849: compilation error in a require()d file", ->
# Create a temporary file to require().
tempFile = path.join os.tmpdir(), 'syntax-error.coffee'
ok not fs.existsSync tempFile
fs.writeFileSync tempFile, 'foo in bar or in baz'
try
assertErrorFormat """
require '#{tempFile.replace /\\/g, '\\\\'}'
""",
"""
#{fs.realpathSync tempFile}:1:15: error: unexpected in
foo in bar or in baz
^^
"""
finally
fs.unlinkSync tempFile
test "#3890: Error.prepareStackTrace doesn't throw an error if a compiled file is deleted", ->
# Adapted from https://github.com/atom/coffee-cash/blob/master/spec/coffee-cash-spec.coffee
filePath = path.join os.tmpdir(), 'PrepareStackTraceTestFile.coffee'
fs.writeFileSync filePath, "module.exports = -> throw new Error('hello world')"
throwsAnError = require filePath
fs.unlinkSync filePath
try
throwsAnError()
catch error
eq error.message, 'hello world'
doesNotThrow(-> error.stack)
notEqual error.stack.toString().indexOf(filePath), -1
test "#4418: stack traces for compiled files reference the correct line number", ->
# The browser is already compiling other anonymous scripts (the tests)
# which will conflict.
return if global.testingBrowser
filePath = path.join os.tmpdir(), 'StackTraceLineNumberTestFile.coffee'
fileContents = """
testCompiledFileStackTraceLineNumber = ->
# `a` on the next line is undefined and should throw a ReferenceError
console.log a if true
do testCompiledFileStackTraceLineNumber
"""
fs.writeFileSync filePath, fileContents
try
require filePath
catch error
fs.unlinkSync filePath
# Make sure the line number reported is line 3 (the original Coffee source)
# and not line 6 (the generated JavaScript).
eq /StackTraceLineNumberTestFile.coffee:(\d)/.exec(error.stack.toString())[1], '3'
test "#4418: stack traces for compiled strings reference the correct line number", ->
# The browser is already compiling other anonymous scripts (the tests)
# which will conflict.
return if global.testingBrowser
try
CoffeeScript.run '''
testCompiledStringStackTraceLineNumber = ->
# `a` on the next line is undefined and should throw a ReferenceError
console.log a if true
do testCompiledStringStackTraceLineNumber
'''
catch error
# Make sure the line number reported is line 3 (the original Coffee source)
# and not line 6 (the generated JavaScript).
eq /testCompiledStringStackTraceLineNumber.*:(\d):/.exec(error.stack.toString())[1], '3'
test "#4558: compiling a string inside a script doesnt screw up stack trace line number", ->
# The browser is already compiling other anonymous scripts (the tests)
# which will conflict.
return if global.testingBrowser
try
CoffeeScript.run '''
testCompilingInsideAScriptDoesntScrewUpStackTraceLineNumber = ->
if require?
CoffeeScript = require './lib/coffeescript'
CoffeeScript.compile ''
throw new Error 'Some Error'
do testCompilingInsideAScriptDoesntScrewUpStackTraceLineNumber
'''
catch error
# Make sure the line number reported is line 5 (the original Coffee source)
# and not line 10 (the generated JavaScript).
eq /testCompilingInsideAScriptDoesntScrewUpStackTraceLineNumber.*:(\d):/.exec(error.stack.toString())[1], '5'
test "#1096: unexpected generated tokens", ->
# Implicit ends
assertErrorFormat 'a:, b', '''
[stdin]:1:3: error: unexpected ,
a:, b
^
'''
# Explicit ends
assertErrorFormat '(a:)', '''
[stdin]:1:4: error: unexpected )
(a:)
^
'''
# Unexpected end of file
assertErrorFormat 'a:', '''
[stdin]:1:3: error: unexpected end of input
a:
^
'''
assertErrorFormat 'a +', '''
[stdin]:1:4: error: unexpected end of input
a +
^
'''
# Unexpected key in implicit object (an implicit object itself is _not_
# unexpected here)
assertErrorFormat '''
for i in [1]:
1
''', '''
[stdin]:2:4: error: unexpected end of input
1
^
'''
# Unexpected regex
assertErrorFormat '{/a/i: val}', '''
[stdin]:1:2: error: unexpected regex
{/a/i: val}
^^^^
'''
assertErrorFormat '{///a///i: val}', '''
[stdin]:1:2: error: unexpected regex
{///a///i: val}
^^^^^^^^
'''
assertErrorFormat '{///#{a}///i: val}', '''
[stdin]:1:2: error: unexpected regex
{///#{a}///i: val}
^^^^^^^^^^^
'''
# Unexpected string
assertErrorFormat 'import foo from "lib-#{version}"', '''
[stdin]:1:17: error: the name of the module to be imported from must be an uninterpolated string
import foo from "lib-#{version}"
^^^^^^^^^^^^^^^^
'''
# Unexpected number
assertErrorFormat '"a"0x00Af2', '''
[stdin]:1:4: error: unexpected number
"a"0x00Af2
^^^^^^^
'''
test "#1316: unexpected end of interpolation", ->
assertErrorFormat '''
"#{+}"
''', '''
[stdin]:1:5: error: unexpected end of interpolation
"#{+}"
^
'''
assertErrorFormat '''
"#{++}"
''', '''
[stdin]:1:6: error: unexpected end of interpolation
"#{++}"
^
'''
assertErrorFormat '''
"#{-}"
''', '''
[stdin]:1:5: error: unexpected end of interpolation
"#{-}"
^
'''
assertErrorFormat '''
"#{--}"
''', '''
[stdin]:1:6: error: unexpected end of interpolation
"#{--}"
^
'''
assertErrorFormat '''
"#{~}"
''', '''
[stdin]:1:5: error: unexpected end of interpolation
"#{~}"
^
'''
assertErrorFormat '''
"#{!}"
''', '''
[stdin]:1:5: error: unexpected end of interpolation
"#{!}"
^
'''
assertErrorFormat '''
"#{not}"
''', '''
[stdin]:1:7: error: unexpected end of interpolation
"#{not}"
^
'''
assertErrorFormat '''
"#{5) + (4}_"
''', '''
[stdin]:1:5: error: unmatched )
"#{5) + (4}_"
^
'''
# #2918
assertErrorFormat '''
"#{foo.}"
''', '''
[stdin]:1:8: error: unexpected end of interpolation
"#{foo.}"
^
'''
test "#3325: implicit indentation errors", ->
assertErrorFormat '''
i for i in a then i
''', '''
[stdin]:1:14: error: unexpected then
i for i in a then i
^^^^
'''
test "explicit indentation errors", ->
assertErrorFormat '''
a = b
c
''', '''
[stdin]:2:1: error: unexpected indentation
c
^^
'''
test "unclosed strings", ->
assertErrorFormat '''
'
''', '''
[stdin]:1:1: error: missing '
'
^
'''
assertErrorFormat '''
"
''', '''
[stdin]:1:1: error: missing "
"
^
'''
assertErrorFormat """
'''
""", """
[stdin]:1:1: error: missing '''
'''
^^^
"""
assertErrorFormat '''
"""
''', '''
[stdin]:1:1: error: missing """
"""
^^^
'''
assertErrorFormat '''
"#{"
''', '''
[stdin]:1:4: error: missing "
"#{"
^
'''
assertErrorFormat '''
"""#{"
''', '''
[stdin]:1:6: error: missing "
"""#{"
^
'''
assertErrorFormat '''
"#{"""
''', '''
[stdin]:1:4: error: missing """
"#{"""
^^^
'''
assertErrorFormat '''
"""#{"""
''', '''
[stdin]:1:6: error: missing """
"""#{"""
^^^
'''
assertErrorFormat '''
///#{"""
''', '''
[stdin]:1:6: error: missing """
///#{"""
^^^
'''
assertErrorFormat '''
"a
#{foo """
bar
#{ +'12 }
baz
"""} b"
''', '''
[stdin]:4:11: error: missing '
#{ +'12 }
^
'''
# https://github.com/jashkenas/coffeescript/issues/3301#issuecomment-31735168
assertErrorFormat '''
# Note the double escaping; this would be `"""a\"""` real code.
"""a\\"""
''', '''
[stdin]:2:1: error: missing """
"""a\\"""
^^^
'''
test "unclosed heregexes", ->
assertErrorFormat '''
///
''', '''
[stdin]:1:1: error: missing ///
///
^^^
'''
# https://github.com/jashkenas/coffeescript/issues/3301#issuecomment-31735168
assertErrorFormat '''
# Note the double escaping; this would be `///a\///` real code.
///a\\///
''', '''
[stdin]:2:1: error: missing ///
///a\\///
^^^
'''
test "unexpected token after string", ->
# Parsing error.
assertErrorFormat '''
'foo'bar
''', '''
[stdin]:1:6: error: unexpected identifier
'foo'bar
^^^
'''
assertErrorFormat '''
"foo"bar
''', '''
[stdin]:1:6: error: unexpected identifier
"foo"bar
^^^
'''
# Lexing error.
assertErrorFormat '''
'foo'bar'
''', '''
[stdin]:1:9: error: missing '
'foo'bar'
^
'''
assertErrorFormat '''
"foo"bar"
''', '''
[stdin]:1:9: error: missing "
"foo"bar"
^
'''
test "#3348: Location data is wrong in interpolations with leading whitespace", ->
assertErrorFormat '''
"#{ * }"
''', '''
[stdin]:1:5: error: unexpected *
"#{ * }"
^
'''
test "octal escapes", ->
assertErrorFormat '''
"a\\0\\tb\\\\\\07c"
''', '''
[stdin]:1:10: error: octal escape sequences are not allowed \\07
"a\\0\\tb\\\\\\07c"
\ \ \ \ ^\^^
'''
assertErrorFormat '''
"a
#{b} \\1"
''', '''
[stdin]:2:8: error: octal escape sequences are not allowed \\1
#{b} \\1"
^\^
'''
assertErrorFormat '''
/a\\0\\tb\\\\\\07c/
''', '''
[stdin]:1:10: error: octal escape sequences are not allowed \\07
/a\\0\\tb\\\\\\07c/
\ \ \ \ ^\^^
'''
assertErrorFormat '''
/a\\1\\tb\\\\\\07c/
''', '''
[stdin]:1:10: error: octal escape sequences are not allowed \\07
/a\\1\\tb\\\\\\07c/
\ \ \ \ ^\^^
'''
assertErrorFormat '''
///a
#{b} \\01///
''', '''
[stdin]:2:8: error: octal escape sequences are not allowed \\01
#{b} \\01///
^\^^
'''
test "#3795: invalid escapes", ->
assertErrorFormat '''
"a\\0\\tb\\\\\\x7g"
''', '''
[stdin]:1:10: error: invalid escape sequence \\x7g
"a\\0\\tb\\\\\\x7g"
\ \ \ \ ^\^^^
'''
assertErrorFormat '''
"a
#{b} \\uA02
c"
''', '''
[stdin]:2:8: error: invalid escape sequence \\uA02
#{b} \\uA02
^\^^^^
'''
assertErrorFormat '''
/a\\u002space/
''', '''
[stdin]:1:3: error: invalid escape sequence \\u002s
/a\\u002space/
^\^^^^^
'''
assertErrorFormat '''
///a \\u002 0 space///
''', '''
[stdin]:1:6: error: invalid escape sequence \\u002 \n\
///a \\u002 0 space///
^\^^^^^
'''
assertErrorFormat '''
///a
#{b} \\x0
c///
''', '''
[stdin]:2:8: error: invalid escape sequence \\x0
#{b} \\x0
^\^^
'''
assertErrorFormat '''
/ab\\u/
''', '''
[stdin]:1:4: error: invalid escape sequence \\u
/ab\\u/
^\^
'''
test "illegal herecomment", ->
assertErrorFormat '''
###
Regex: /a*/g
###
''', '''
[stdin]:2:12: error: block comments cannot contain */
Regex: /a*/g
^^
'''
test "#1724: regular expressions beginning with *", ->
assertErrorFormat '''
/* foo/
''', '''
[stdin]:1:2: error: regular expressions cannot begin with *
/* foo/
^
'''
assertErrorFormat '''
///
* foo
///
''', '''
[stdin]:2:3: error: regular expressions cannot begin with *
* foo
^
'''
test "invalid regex flags", ->
assertErrorFormat '''
/a/ii
''', '''
[stdin]:1:4: error: invalid regular expression flags ii
/a/ii
^^
'''
assertErrorFormat '''
/a/G
''', '''
[stdin]:1:4: error: invalid regular expression flags G
/a/G
^
'''
assertErrorFormat '''
/a/gimi
''', '''
[stdin]:1:4: error: invalid regular expression flags gimi
/a/gimi
^^^^
'''
assertErrorFormat '''
/a/g_
''', '''
[stdin]:1:4: error: invalid regular expression flags g_
/a/g_
^^
'''
assertErrorFormat '''
///a///ii
''', '''
[stdin]:1:8: error: invalid regular expression flags ii
///a///ii
^^
'''
doesNotThrow -> CoffeeScript.compile '/a/ymgi'
test "missing `)`, `}`, `]`", ->
assertErrorFormat '''
(
''', '''
[stdin]:1:1: error: missing )
(
^
'''
assertErrorFormat '''
{
''', '''
[stdin]:1:1: error: missing }
{
^
'''
assertErrorFormat '''
[
''', '''
[stdin]:1:1: error: missing ]
[
^
'''
assertErrorFormat '''
obj = {a: [1, (2+
''', '''
[stdin]:1:15: error: missing )
obj = {a: [1, (2+
^
'''
assertErrorFormat '''
"#{
''', '''
[stdin]:1:3: error: missing }
"#{
^
'''
assertErrorFormat '''
"""
foo#{ bar "#{1}"
''', '''
[stdin]:2:7: error: missing }
foo#{ bar "#{1}"
^
'''
test "unclosed regexes", ->
assertErrorFormat '''
/
''', '''
[stdin]:1:1: error: missing / (unclosed regex)
/
^
'''
assertErrorFormat '''
# Note the double escaping; this would be `/a\/` real code.
/a\\/
''', '''
[stdin]:2:1: error: missing / (unclosed regex)
/a\\/
^
'''
assertErrorFormat '''
/// ^
a #{""" ""#{if /[/].test "|" then 1 else 0}"" """}
///
''', '''
[stdin]:2:18: error: missing / (unclosed regex)
a #{""" ""#{if /[/].test "|" then 1 else 0}"" """}
^
'''
test "duplicate function arguments", ->
assertErrorFormat '''
(foo, bar, foo) ->
''', '''
[stdin]:1:12: error: multiple parameters named 'foo'
(foo, bar, foo) ->
^^^
'''
assertErrorFormat '''
(@foo, bar, @foo) ->
''', '''
[stdin]:1:13: error: multiple parameters named '@foo'
(@foo, bar, @foo) ->
^^^^
'''
test "reserved words", ->
assertErrorFormat '''
case
''', '''
[stdin]:1:1: error: reserved word 'case'
case
^^^^
'''
assertErrorFormat '''
case = 1
''', '''
[stdin]:1:1: error: reserved word 'case'
case = 1
^^^^
'''
assertErrorFormat '''
for = 1
''', '''
[stdin]:1:1: error: keyword 'for' can't be assigned
for = 1
^^^
'''
assertErrorFormat '''
unless = 1
''', '''
[stdin]:1:1: error: keyword 'unless' can't be assigned
unless = 1
^^^^^^
'''
assertErrorFormat '''
for += 1
''', '''
[stdin]:1:1: error: keyword 'for' can't be assigned
for += 1
^^^
'''
assertErrorFormat '''
for &&= 1
''', '''
[stdin]:1:1: error: keyword 'for' can't be assigned
for &&= 1
^^^
'''
# Make sure token look-behind doesn't go out of range.
assertErrorFormat '''
&&= 1
''', '''
[stdin]:1:1: error: unexpected &&=
&&= 1
^^^
'''
# #2306: Show unaliased name in error messages.
assertErrorFormat '''
on = 1
''', '''
[stdin]:1:1: error: keyword 'on' can't be assigned
on = 1
^^
'''
test "strict mode errors", ->
assertErrorFormat '''
eval = 1
''', '''
[stdin]:1:1: error: 'eval' can't be assigned
eval = 1
^^^^
'''
assertErrorFormat '''
class eval
''', '''
[stdin]:1:7: error: 'eval' can't be assigned
class eval
^^^^
'''
assertErrorFormatAst '''
arguments++
''', '''
[stdin]:1:1: error: 'arguments' can't be assigned
arguments++
^^^^^^^^^
'''
assertErrorFormatAst '''
--arguments
''', '''
[stdin]:1:3: error: 'arguments' can't be assigned
--arguments
^^^^^^^^^
'''
test "invalid numbers", ->
assertErrorFormat '''
0X0
''', '''
[stdin]:1:2: error: radix prefix in '0X0' must be lowercase
0X0
^
'''
assertErrorFormat '''
10E0
''', '''
[stdin]:1:3: error: exponential notation in '10E0' must be indicated with a lowercase 'e'
10E0
^
'''
assertErrorFormat '''
018
''', '''
[stdin]:1:1: error: decimal literal '018' must not be prefixed with '0'
018
^^^
'''
assertErrorFormat '''
010
''', '''
[stdin]:1:1: error: octal literal '010' must be prefixed with '0o'
010
^^^
'''
test "unexpected object keys", ->
assertErrorFormat '''
{(a + "b")}
''', '''
[stdin]:1:11: error: unexpected }
{(a + "b")}
^
'''
assertErrorFormat '''
{(a + "b"): 1}
''', '''
[stdin]:1:11: error: unexpected :
{(a + "b"): 1}
^
'''
assertErrorFormat '''
(a + "b"): 1
''', '''
[stdin]:1:10: error: unexpected :
(a + "b"): 1
^
'''
test "invalid object keys", ->
assertErrorFormat '''
@a: 1
''', '''
[stdin]:1:1: error: invalid object key
@a: 1
^^
'''
assertErrorFormat '''
f
@a: 1
''', '''
[stdin]:2:3: error: invalid object key
@a: 1
^^
'''
assertErrorFormat '''
{a=2}
''', '''
[stdin]:1:3: error: unexpected =
{a=2}
^
'''
test "invalid destructuring default target", ->
assertErrorFormat '''
{'a' = 2} = obj
''', '''
[stdin]:1:6: error: unexpected =
{'a' = 2} = obj
^
'''
test "#4070: lone expansion", ->
assertErrorFormat '''
[...] = a
''', '''
[stdin]:1:2: error: Destructuring assignment has no target
[...] = a
^^^
'''
assertErrorFormat '''
[ ..., ] = a
''', '''
[stdin]:1:3: error: Destructuring assignment has no target
[ ..., ] = a
^^^
'''
test "#3926: implicit object in parameter list", ->
assertErrorFormat '''
(a: b) ->
''', '''
[stdin]:1:3: error: unexpected :
(a: b) ->
^
'''
assertErrorFormat '''
(one, two, {three, four: five}, key: value) ->
''', '''
[stdin]:1:36: error: unexpected :
(one, two, {three, four: five}, key: value) ->
^
'''
test "#4130: unassignable in destructured param", ->
assertErrorFormat '''
fun = ({
@param : null
}) ->
console.log "Oh hello!"
''', '''
[stdin]:2:12: error: keyword 'null' can't be assigned
@param : null
^^^^
'''
assertErrorFormat '''
({a: null}) ->
''', '''
[stdin]:1:6: error: keyword 'null' can't be assigned
({a: null}) ->
^^^^
'''
assertErrorFormat '''
({a: 1}) ->
''', '''
[stdin]:1:6: error: '1' can't be assigned
({a: 1}) ->
^
'''
assertErrorFormat '''
({1}) ->
''', '''
[stdin]:1:3: error: '1' can't be assigned
({1}) ->
^
'''
assertErrorFormat '''
({a: true = 1}) ->
''', '''
[stdin]:1:6: error: keyword 'true' can't be assigned
({a: true = 1}) ->
^^^^
'''
test "`yield` outside of a function", ->
assertErrorFormatAst '''
yield 1
''', '''
[stdin]:1:1: error: yield can only occur inside functions
yield 1
^^^^^^^
'''
assertErrorFormatAst '''
yield return
''', '''
[stdin]:1:1: error: yield can only occur inside functions
yield return
^^^^^^^^^^^^
'''
test "#4097: `yield return` as an expression", ->
assertErrorFormat '''
-> (yield return)
''', '''
[stdin]:1:5: error: cannot use a pure statement in an expression
-> (yield return)
^^^^^^^^^^^^
'''
test "#5013: `await return` as an expression", ->
assertErrorFormat '''
-> (await return)
''', '''
[stdin]:1:5: error: cannot use a pure statement in an expression
-> (await return)
^^^^^^^^^^^^
'''
test "#5013: `return` as an expression", ->
assertErrorFormat '''
-> (return)
''', '''
[stdin]:1:5: error: cannot use a pure statement in an expression
-> (return)
^^^^^^
'''
test "#5013: `break` as an expression", ->
assertErrorFormat '''
(b = 1; break) for b in a
''', '''
[stdin]:1:9: error: cannot use a pure statement in an expression
(b = 1; break) for b in a
^^^^^
'''
test "#5013: `continue` as an expression", ->
assertErrorFormat '''
(b = 1; continue) for b in a
''', '''
[stdin]:1:9: error: cannot use a pure statement in an expression
(b = 1; continue) for b in a
^^^^^^^^
'''
test "`&&=` and `||=` with a space in-between", ->
assertErrorFormat '''
a = 0
a && = 1
''', '''
[stdin]:2:6: error: unexpected =
a && = 1
^
'''
assertErrorFormat '''
a = 0
a and = 1
''', '''
[stdin]:2:7: error: unexpected =
a and = 1
^
'''
assertErrorFormat '''
a = 0
a || = 1
''', '''
[stdin]:2:6: error: unexpected =
a || = 1
^
'''
assertErrorFormat '''
a = 0
a or = 1
''', '''
[stdin]:2:6: error: unexpected =
a or = 1
^
'''
test "anonymous functions cannot be exported", ->
assertErrorFormat '''
export ->
console.log 'hello, world!'
''', '''
[stdin]:1:8: error: unexpected ->
export ->
^^
'''
test "anonymous classes cannot be exported", ->
assertErrorFormat '''
export class
constructor: ->
console.log 'hello, world!'
''', '''
[stdin]:1:8: error: anonymous classes cannot be exported
export class
^^^^^
'''
test "unless enclosed by curly braces, only * can be aliased", ->
assertErrorFormat '''
import foo as bar from 'lib'
''', '''
[stdin]:1:12: error: unexpected as
import foo as bar from 'lib'
^^
'''
test "unwrapped imports must follow constrained syntax", ->
assertErrorFormat '''
import foo, bar from 'lib'
''', '''
[stdin]:1:13: error: unexpected identifier
import foo, bar from 'lib'
^^^
'''
assertErrorFormat '''
import foo, bar, baz from 'lib'
''', '''
[stdin]:1:13: error: unexpected identifier
import foo, bar, baz from 'lib'
^^^
'''
assertErrorFormat '''
import foo, bar as baz from 'lib'
''', '''
[stdin]:1:13: error: unexpected identifier
import foo, bar as baz from 'lib'
^^^
'''
test "cannot export * without a module to export from", ->
assertErrorFormat '''
export *
''', '''
[stdin]:1:9: error: unexpected end of input
export *
^
'''
test "imports and exports must be top-level", ->
assertErrorFormat '''
if foo
import { bar } from 'lib'
''', '''
[stdin]:2:3: error: import statements must be at top-level scope
import { bar } from 'lib'
^^^^^^^^^^^^^^^^^^^^^^^^^
'''
assertErrorFormat '''
foo = ->
export { bar }
''', '''
[stdin]:2:3: error: export statements must be at top-level scope
export { bar }
^^^^^^^^^^^^^^
'''
test "cannot import the same member more than once", ->
assertErrorFormat '''
import { foo, foo } from 'lib'
''', '''
[stdin]:1:15: error: 'foo' has already been declared
import { foo, foo } from 'lib'
^^^
'''
assertErrorFormat '''
import { foo, bar, foo } from 'lib'
''', '''
[stdin]:1:20: error: 'foo' has already been declared
import { foo, bar, foo } from 'lib'
^^^
'''
assertErrorFormat '''
import { foo, bar as foo } from 'lib'
''', '''
[stdin]:1:15: error: 'foo' has already been declared
import { foo, bar as foo } from 'lib'
^^^^^^^^^^
'''
assertErrorFormat '''
import foo, { foo } from 'lib'
''', '''
[stdin]:1:15: error: 'foo' has already been declared
import foo, { foo } from 'lib'
^^^
'''
assertErrorFormat '''
import foo, { bar as foo } from 'lib'
''', '''
[stdin]:1:15: error: 'foo' has already been declared
import foo, { bar as foo } from 'lib'
^^^^^^^^^^
'''
assertErrorFormat '''
import foo from 'libA'
import foo from 'libB'
''', '''
[stdin]:2:8: error: 'foo' has already been declared
import foo from 'libB'
^^^
'''
assertErrorFormat '''
import * as foo from 'libA'
import { foo } from 'libB'
''', '''
[stdin]:2:10: error: 'foo' has already been declared
import { foo } from 'libB'
^^^
'''
test "imported members cannot be reassigned", ->
assertErrorFormat '''
import { foo } from 'lib'
foo = 'bar'
''', '''
[stdin]:2:1: error: 'foo' is read-only
foo = 'bar'
^^^
'''
assertErrorFormat '''
import { foo } from 'lib'
export default foo = 'bar'
''', '''
[stdin]:2:16: error: 'foo' is read-only
export default foo = 'bar'
^^^
'''
assertErrorFormat '''
import { foo } from 'lib'
export foo = 'bar'
''', '''
[stdin]:2:8: error: 'foo' is read-only
export foo = 'bar'
^^^
'''
test "bound functions cannot be generators", ->
assertErrorFormat 'f = => yield this', '''
[stdin]:1:8: error: yield cannot occur inside bound (fat arrow) functions
f = => yield this
^^^^^^^^^^
'''
test "#4790: bound functions cannot be generators, even when were creating IIFEs", ->
assertErrorFormat '''
=>
for x in []
for y in []
yield z
''', '''
[stdin]:4:7: error: yield cannot occur inside bound (fat arrow) functions
yield z
^^^^^^^
'''
test "CoffeeScript keywords cannot be used as unaliased names in import lists", ->
assertErrorFormat """
import { unless, baz as bar } from 'lib'
bar.barMethod()
""", '''
[stdin]:1:10: error: unexpected unless
import { unless, baz as bar } from 'lib'
^^^^^^
'''
test "CoffeeScript keywords cannot be used as local names in import list aliases", ->
assertErrorFormat """
import { bar as unless, baz as bar } from 'lib'
bar.barMethod()
""", '''
[stdin]:1:17: error: unexpected unless
import { bar as unless, baz as bar } from 'lib'
^^^^^^
'''
test "cannot have `await` outside a function", ->
assertErrorFormatAst '''
await 1
''', '''
[stdin]:1:1: error: await can only occur inside functions
await 1
^^^^^^^
'''
assertErrorFormatAst '''
await return
''', '''
[stdin]:1:1: error: await can only occur inside functions
await return
^^^^^^^^^^^^
'''
test "indexes are not supported in for-from loops", ->
assertErrorFormat "x for x, i from [1, 2, 3]", '''
[stdin]:1:10: error: cannot use index with for-from
x for x, i from [1, 2, 3]
^
'''
test "own is not supported in for-from loops", ->
assertErrorFormat "x for own x from [1, 2, 3]", '''
[stdin]:1:7: error: cannot use own with for-from
x for own x from [1, 2, 3]
^^^
'''
test "tagged template literals must be called by an identifier", ->
assertErrorFormat "1''", '''
[stdin]:1:1: error: literal is not a function
1''
^
'''
assertErrorFormat '1""', '''
[stdin]:1:1: error: literal is not a function
1""
^
'''
assertErrorFormat "1'b'", '''
[stdin]:1:1: error: literal is not a function
1'b'
^
'''
assertErrorFormat '1"b"', '''
[stdin]:1:1: error: literal is not a function
1"b"
^
'''
assertErrorFormat "1'''b'''", """
[stdin]:1:1: error: literal is not a function
1'''b'''
^
"""
assertErrorFormat '1"""b"""', '''
[stdin]:1:1: error: literal is not a function
1"""b"""
^
'''
assertErrorFormat '1"#{b}"', '''
[stdin]:1:1: error: literal is not a function
1"#{b}"
^
'''
assertErrorFormat '1"""#{b}"""', '''
[stdin]:1:1: error: literal is not a function
1"""#{b}"""
^
'''
test "constructor functions can't be async", ->
assertErrorFormat 'class then constructor: -> await x', '''
[stdin]:1:12: error: Class constructor may not be async
class then constructor: -> await x
^^^^^^^^^^^
'''
test "constructor functions can't be generators", ->
assertErrorFormat 'class then constructor: -> yield', '''
[stdin]:1:12: error: Class constructor may not be a generator
class then constructor: -> yield
^^^^^^^^^^^
'''
test "non-derived constructors can't call super", ->
assertErrorFormat 'class then constructor: -> super()', '''
[stdin]:1:28: error: 'super' is only allowed in derived class constructors
class then constructor: -> super()
^^^^^^^
'''
test "derived constructors can't reference `this` before calling super", ->
assertErrorFormat 'class extends A then constructor: -> @', '''
[stdin]:1:38: error: Can't reference 'this' before calling super in derived class constructors
class extends A then constructor: -> @
^
'''
test "derived constructors can't use @params without calling super", ->
assertErrorFormat 'class extends A then constructor: (@a) ->', '''
[stdin]:1:36: error: Can't use @params in derived class constructors without calling super
class extends A then constructor: (@a) ->
^^
'''
test "derived constructors can't call super with @params", ->
assertErrorFormat 'class extends A then constructor: (@a) -> super(@a)', '''
[stdin]:1:49: error: Can't call super with @params in derived class constructors
class extends A then constructor: (@a) -> super(@a)
^^
'''
test "derived constructors can't call super with buried @params", ->
assertErrorFormat 'class extends A then constructor: (@a) -> super((=> @a)())', '''
[stdin]:1:53: error: Can't call super with @params in derived class constructors
class extends A then constructor: (@a) -> super((=> @a)())
^^
'''
test "'super' is not allowed in constructor parameter defaults", ->
assertErrorFormat 'class extends A then constructor: (a = super()) ->', '''
[stdin]:1:40: error: 'super' is not allowed in constructor parameter defaults
class extends A then constructor: (a = super()) ->
^^^^^^^
'''
test "can't use pattern matches for loop indices", ->
assertErrorFormat 'a for b, {c} in d', '''
[stdin]:1:10: error: index cannot be a pattern matching expression
a for b, {c} in d
^^^
'''
test "bare 'super' is no longer allowed", ->
# TODO Improve this error message (it should at least be 'unexpected super')
assertErrorFormat 'class extends A then constructor: -> super', '''
[stdin]:1:35: error: unexpected ->
class extends A then constructor: -> super
^^
'''
test "soaked 'super' in constructor", ->
assertErrorFormat 'class extends A then constructor: -> super?()', '''
[stdin]:1:38: error: Unsupported reference to 'super'
class extends A then constructor: -> super?()
^^^^^
'''
test "new with 'super'", ->
assertErrorFormat 'class extends A then foo: -> new super()', '''
[stdin]:1:34: error: Unsupported reference to 'super'
class extends A then foo: -> new super()
^^^^^
'''
test "getter keyword in object", ->
assertErrorFormat '''
obj =
get foo: ->
''', '''
[stdin]:2:3: error: 'get' cannot be used as a keyword, or as a function call without parentheses
get foo: ->
^^^
'''
test "setter keyword in object", ->
assertErrorFormat '''
obj =
set foo: ->
''', '''
[stdin]:2:3: error: 'set' cannot be used as a keyword, or as a function call without parentheses
set foo: ->
^^^
'''
test "getter keyword in inline implicit object", ->
assertErrorFormat 'obj = get foo: ->', '''
[stdin]:1:7: error: 'get' cannot be used as a keyword, or as a function call without parentheses
obj = get foo: ->
^^^
'''
test "setter keyword in inline implicit object", ->
assertErrorFormat 'obj = set foo: ->', '''
[stdin]:1:7: error: 'set' cannot be used as a keyword, or as a function call without parentheses
obj = set foo: ->
^^^
'''
test "getter keyword in inline explicit object", ->
assertErrorFormat 'obj = {get foo: ->}', '''
[stdin]:1:8: error: 'get' cannot be used as a keyword, or as a function call without parentheses
obj = {get foo: ->}
^^^
'''
test "setter keyword in inline explicit object", ->
assertErrorFormat 'obj = {set foo: ->}', '''
[stdin]:1:8: error: 'set' cannot be used as a keyword, or as a function call without parentheses
obj = {set foo: ->}
^^^
'''
test "getter keyword in function", ->
assertErrorFormat '''
f = ->
get foo: ->
''', '''
[stdin]:2:3: error: 'get' cannot be used as a keyword, or as a function call without parentheses
get foo: ->
^^^
'''
test "setter keyword in function", ->
assertErrorFormat '''
f = ->
set foo: ->
''', '''
[stdin]:2:3: error: 'set' cannot be used as a keyword, or as a function call without parentheses
set foo: ->
^^^
'''
test "getter keyword in inline function", ->
assertErrorFormat 'f = -> get foo: ->', '''
[stdin]:1:8: error: 'get' cannot be used as a keyword, or as a function call without parentheses
f = -> get foo: ->
^^^
'''
test "setter keyword in inline function", ->
assertErrorFormat 'f = -> set foo: ->', '''
[stdin]:1:8: error: 'set' cannot be used as a keyword, or as a function call without parentheses
f = -> set foo: ->
^^^
'''
test "getter keyword in class", ->
assertErrorFormat '''
class A
get foo: ->
''', '''
[stdin]:2:3: error: 'get' cannot be used as a keyword, or as a function call without parentheses
get foo: ->
^^^
'''
test "setter keyword in class", ->
assertErrorFormat '''
class A
set foo: ->
''', '''
[stdin]:2:3: error: 'set' cannot be used as a keyword, or as a function call without parentheses
set foo: ->
^^^
'''
test "getter keyword in inline class", ->
assertErrorFormat 'class A then get foo: ->', '''
[stdin]:1:14: error: 'get' cannot be used as a keyword, or as a function call without parentheses
class A then get foo: ->
^^^
'''
test "setter keyword in inline class", ->
assertErrorFormat 'class A then set foo: ->', '''
[stdin]:1:14: error: 'set' cannot be used as a keyword, or as a function call without parentheses
class A then set foo: ->
^^^
'''
test "getter keyword before static method", ->
assertErrorFormat '''
class A
get @foo = ->
''', '''
[stdin]:2:3: error: 'get' cannot be used as a keyword, or as a function call without parentheses
get @foo = ->
^^^
'''
test "setter keyword before static method", ->
assertErrorFormat '''
class A
set @foo = ->
''', '''
[stdin]:2:3: error: 'set' cannot be used as a keyword, or as a function call without parentheses
set @foo = ->
^^^
'''
test "#4248: Unicode code point escapes", ->
assertErrorFormat '''
"a
#{b} \\u{G02}
c"
''', '''
[stdin]:2:8: error: invalid escape sequence \\u{G02}
#{b} \\u{G02}
^\^^^^^^
'''
assertErrorFormat '''
/a\\u{}b/
''', '''
[stdin]:1:3: error: invalid escape sequence \\u{}
/a\\u{}b/
^\^^^
'''
assertErrorFormat '''
///a \\u{01abc///
''', '''
[stdin]:1:6: error: invalid escape sequence \\u{01abc
///a \\u{01abc///
^\^^^^^^^
'''
assertErrorFormat '''
/\\u{123} \\u{110000}/
''', '''
[stdin]:1:10: error: unicode code point escapes greater than \\u{10ffff} are not allowed
/\\u{123} \\u{110000}/
\ ^\^^^^^^^^^
'''
assertErrorFormat '''
///abc\\\\\\u{123456}///u
''', '''
[stdin]:1:9: error: unicode code point escapes greater than \\u{10ffff} are not allowed
///abc\\\\\\u{123456}///u
\ \^\^^^^^^^^^
'''
assertErrorFormat '''
"""
\\u{123}
a
\\u{00110000}
#{ 'b' }
"""
''', '''
[stdin]:4:5: error: unicode code point escapes greater than \\u{10ffff} are not allowed
\\u{00110000}
^\^^^^^^^^^^^
'''
assertErrorFormat '''
'\\u{a}\\u{1111110000}'
''', '''
[stdin]:1:7: error: unicode code point escapes greater than \\u{10ffff} are not allowed
'\\u{a}\\u{1111110000}'
\ ^\^^^^^^^^^^^^^
'''
test "JSX error: non-matching tag names", ->
assertErrorFormat '''
<div><span></div></span>
''',
'''
[stdin]:1:7: error: expected corresponding JSX closing tag for span
<div><span></div></span>
^^^^
'''
test "JSX error: bare expressions not allowed", ->
assertErrorFormat '''
<div x=3 />
''',
'''
[stdin]:1:8: error: expected wrapped or quoted JSX attribute
<div x=3 />
^
'''
test "JSX error: unescaped opening tag angle bracket disallowed", ->
assertErrorFormat '''
<Person><<</Person>
''',
'''
[stdin]:1:9: error: unexpected <<
<Person><<</Person>
^^
'''
test "JSX error: ambiguous tag-like expression", ->
assertErrorFormat '''
x = a <b > c
''',
'''
[stdin]:1:10: error: missing </
x = a <b > c
^
'''
test 'JSX error: invalid attributes', ->
assertErrorFormatAst '''
<div a="b" {props} />
''', '''
[stdin]:1:12: error: Unexpected token. Allowed JSX attributes are: id="val", src={source}, {props...} or attribute.
<div a="b" {props} />
^^^^^^^
'''
assertErrorFormatAst '''
<div a={b} {a:{b}} />
''', '''
[stdin]:1:12: error: Unexpected token. Allowed JSX attributes are: id="val", src={source}, {props...} or attribute.
<div a={b} {a:{b}} />
^^^^^^^
'''
assertErrorFormatAst '''
<div {"#{a}"} />
''', '''
[stdin]:1:6: error: Unexpected token. Allowed JSX attributes are: id="val", src={source}, {props...} or attribute.
<div {"#{a}"} />
^^^^^^^^
'''
assertErrorFormatAst '''
<div props... />
''', '''
[stdin]:1:11: error: Unexpected token. Allowed JSX attributes are: id="val", src={source}, {props...} or attribute.
<div props... />
^^^
'''
assertErrorFormatAst '''
<div {a:"b", props..., c:d()} />
''', '''
[stdin]:1:6: error: Unexpected token. Allowed JSX attributes are: id="val", src={source}, {props...} or attribute.
<div {a:"b", props..., c:d()} />
^^^^^^^^^^^^^^^^^^^^^^^^
'''
assertErrorFormatAst '''
<div {props..., a, b} />
''', '''
[stdin]:1:6: error: Unexpected token. Allowed JSX attributes are: id="val", src={source}, {props...} or attribute.
<div {props..., a, b} />
^^^^^^^^^^^^^^^^
'''
test '#5034: JSX error: Adjacent JSX elements must be wrapped in an enclosing tag', ->
assertErrorFormat '''
render = -> (
<Row>a</Row>
<Row>b</Row>
)
''', '''
[stdin]:3:3: error: Adjacent JSX elements must be wrapped in an enclosing tag
<Row>b</Row>
^^^^^^^^^^^^
'''
assertErrorFormat '''
render = -> (
a = "foo"
<Row>a</Row>
<Row>b</Row>
)
''', '''
[stdin]:4:3: error: Adjacent JSX elements must be wrapped in an enclosing tag
<Row>b</Row>
^^^^^^^^^^^^
'''
test 'Bound method called as callback before binding throws runtime error', ->
class Base
constructor: ->
f = @derivedBound
try
f()
ok no
catch e
eq e.message, 'Bound instance method accessed before binding'
class Derived extends Base
derivedBound: =>
ok no
d = new Derived
test "#3845/#3446: chain after function glyph (but not inline)", ->
assertErrorFormat '''
a -> .b
''',
'''
[stdin]:1:6: error: unexpected .
a -> .b
^
'''
test "#3906: error for unusual indentation", ->
assertErrorFormat '''
a
c
.d
e(
f)
g
''', '''
[stdin]:2:1: error: unexpected indentation
c
^^
'''
test "#4283: error message for implicit call", ->
assertErrorFormat '''
(a, b c) ->
''', '''
[stdin]:1:5: error: unexpected implicit function call
(a, b c) ->
^
'''
test "#3199: error message for call indented non-object", ->
assertErrorFormat '''
fn = ->
fn
1
''', '''
[stdin]:3:1: error: unexpected indentation
1
^^
'''
test "#3199: error message for call indented comprehension", ->
assertErrorFormat '''
fn = ->
fn
x for x in [1, 2, 3]
''', '''
[stdin]:3:1: error: unexpected indentation
x for x in [1, 2, 3]
^^
'''
test "#3199: error message for return indented non-object", ->
assertErrorFormat '''
return
1
''', '''
[stdin]:2:3: error: unexpected number
1
^
'''
test "#3199: error message for return indented comprehension", ->
assertErrorFormat '''
return
x for x in [1, 2, 3]
''', '''
[stdin]:2:3: error: unexpected identifier
x for x in [1, 2, 3]
^
'''
test "#3199: error message for throw indented non-object", ->
assertErrorFormat '''
throw
1
''', '''
[stdin]:2:3: error: unexpected number
1
^
'''
test "#3199: error message for throw indented comprehension", ->
assertErrorFormat '''
throw
x for x in [1, 2, 3]
''', '''
[stdin]:2:3: error: unexpected identifier
x for x in [1, 2, 3]
^
'''
test "#3199: error message for yield indented non-object", ->
assertErrorFormat '''
->
yield
1
''', '''
[stdin]:3:5: error: unexpected number
1
^
'''
test "#3199: error message for yield indented comprehension", ->
assertErrorFormat '''
->
yield
x for x in [1, 2, 3]
''', '''
[stdin]:3:5: error: unexpected identifier
x for x in [1, 2, 3]
^
'''
test "#3199: error message for await indented non-object", ->
assertErrorFormat '''
->
await
1
''', '''
[stdin]:3:5: error: unexpected number
1
^
'''
test "#3199: error message for await indented comprehension", ->
assertErrorFormat '''
->
await
x for x in [1, 2, 3]
''', '''
[stdin]:3:5: error: unexpected identifier
x for x in [1, 2, 3]
^
'''
test "#3098: suppressed newline should be unsuppressed by semicolon", ->
assertErrorFormat '''
a = ; 5
''', '''
[stdin]:1:5: error: unexpected ;
a = ; 5
^
'''
test "#4811: '///' inside a heregex comment does not close the heregex", ->
assertErrorFormat '''
/// .* # comment ///
''', '''
[stdin]:1:1: error: missing ///
/// .* # comment ///
^^^
'''
test "#3933: prevent implicit calls when cotrol flow is missing `THEN`", ->
assertErrorFormat '''
for a in b do ->
''','''
[stdin]:1:12: error: unexpected do
for a in b do ->
^^
'''
assertErrorFormat '''
for a in b ->
''','''
[stdin]:1:12: error: unexpected ->
for a in b ->
^^
'''
assertErrorFormat '''
for a in b do =>
''','''
[stdin]:1:12: error: unexpected do
for a in b do =>
^^
'''
assertErrorFormat '''
while a do ->
''','''
[stdin]:1:9: error: unexpected do
while a do ->
^^
'''
assertErrorFormat '''
until a do =>
''','''
[stdin]:1:9: error: unexpected do
until a do =>
^^
'''
assertErrorFormat '''
switch
when a ->
''','''
[stdin]:2:10: error: unexpected ->
when a ->
^^
'''
test "`new.target` outside of a function", ->
assertErrorFormatAst '''
new.target
''', '''
[stdin]:1:1: error: new.target can only occur inside functions
new.target
^^^^^^^^^^
'''
test "`new.target` is only allowed meta property", ->
assertErrorFormatAst '''
-> new.something
''', '''
[stdin]:1:4: error: the only valid meta property for new is new.target
-> new.something
^^^^^^^^^^^^^
'''
test "`new.target` cannot be assigned", ->
assertErrorFormatAst '''
->
new.target = b
''', '''
[stdin]:2:14: error: unexpected =
new.target = b
^
'''
test "#4834: dynamic import requires exactly one argument", ->
assertErrorFormat '''
import()
''', '''
[stdin]:1:1: error: import() requires exactly one argument
import()
^^^^^^^^
'''
assertErrorFormat '''
import('x', {})
''', '''
[stdin]:1:1: error: import() requires exactly one argument
import('x', {})
^^^^^^^^^^^^^^^
'''
test "#4834: dynamic import requires explicit call parentheses", ->
assertErrorFormat '''
promise = import 'foo'
''', '''
[stdin]:1:23: error: unexpected end of input
promise = import 'foo'
^
'''