Style and Syntax Rules

CoffeeScript often offers several ways to write the same thing: with or without parentheses and braces, this or @, symbolic or English operators. These rules let a team pick one style and apply it consistently, and flag constructs that are easy to misread.

Rules on this page:

camel_case_classes

Property Value
Default level error
Message Class name should be UpperCamelCased
Options none

Requires class names to be UpperCamelCased. This distinguishes constructor functions, which must be called with new, from ordinary functions.

# Good
class BoaConstrictor
class exports.UserService
class @Router

# Bad
class boaConstrictor
class User_Service

The name must match ^[A-Z_][a-zA-Z\d]*$: it starts with an uppercase letter or underscore and continues with letters and digits only. Namespaced names (exports.Foo, @Foo) are checked on their last part, and anonymous classes (class extends Base) are skipped. The context names the class: class name: boaConstrictor.

empty_constructor_needs_parens

Property Value
Default level ignore
Message Invoking a constructor without parens and without arguments
Options none

Requires parentheses when calling a constructor without arguments:

now = new Date()        # Good
now = new Date          # Bad
client = new api.Client # Bad: chained names are followed to the last identifier

The companion rule non_empty_constructor_needs_parens handles constructors called with arguments.

ensure_comprehensions

Property Value
Default level warn
Message Comprehensions must have parentheses around them
Options none

Catches a classic CoffeeScript bug. Without parentheses, an assignment followed by for is a loop that assigns on every iteration, not a list comprehension:

# Bug: `doubled` ends up as the last value, not an array
doubled = n * 2 for n in numbers

# Correct: the whole comprehension is assigned
doubled = (n * 2 for n in numbers)

The rule does not report:

  • Ordinary for loops with an indented body.
  • Assignments whose left-hand side uses the loop variables, which are clearly intended to run per iteration:
lookup[item.id] = item for item in items

no_backticks

Property Value
Default level error
Message Backticks are forbidden
Options none

Forbids backtick-embedded JavaScript:

x = `void 0`   # Bad

Embedded JavaScript bypasses CoffeeScript's safety and lets JavaScript's "bad parts" such as with and eval sneak in. If you have a legitimate need, wrap that line in an inline directive.

no_empty_param_list

Property Value
Default level ignore
Message Empty parameter list is forbidden
Options none

Forbids empty parentheses in function definitions:

# The empty parameter list here is unnecessary:
myFunction = () ->

# Prefer:
myFunction = ->

no_implicit_braces

Property Value
Default level ignore
Message Implicit braces are forbidden
Options strict (default true)

Forbids object literals written without braces. Implicit braces combined with implicit parentheses can be ambiguous:

# Is this a call with three arguments or four?
myFunction a, b, 1:2, 3:4

# Unambiguous
myFunction(a, b, {1:2, 3:4})

With strict: false, implicit braces are allowed for objects that start on their own line, which keeps the idiomatic multi-line style legal:

# Allowed with strict: false, reported with strict: true
config =
  host: 'localhost'
  port: 8080

Class bodies are not reported.

no_implicit_parens

Property Value
Default level ignore
Message Implicit parens are forbidden
Options strict (default true)

Forbids function calls without parentheses:

# Reported
myFunction a, b, c

# Preferred
myFunction(a, b, c)

With strict: false, implicit parentheses are allowed when the call spans several lines, for example a call whose argument is an indented object:

# Allowed with strict: false
$.ajax
  url: '/api/items'
  method: 'GET'

no_interpolation_in_single_quotes

Property Value
Default level ignore
Message Interpolation in single quoted strings is forbidden
Options none

Single-quoted strings never interpolate, so #{...} inside them is almost always a mistake:

foo = '#{bar}'   # Bad: produces the literal text #{bar}
foo = "#{bar}"   # Good

no_nested_string_interpolation

Property Value
Default level warn
Message Nested string interpolation is forbidden
Options none

Warns about interpolations that contain other interpolated strings, which are hard to read:

# Good
str = "Book by #{firstName.toUpperCase()} #{lastName.toUpperCase()}"

# Bad
str = "Book by #{"#{firstName} #{lastName}".toUpperCase()}"

Deeply nested strings produce a single warning, not one per level. Extract the inner string into a variable to fix it.

no_plusplus

Property Value
Default level ignore
Message The increment and decrement operators are forbidden
Options none

Forbids ++ and --, which some teams consider cryptic because of their prefix/postfix semantics. Use += 1 and -= 1. The context shows the operator found, for example found '++'.

no_stand_alone_at

Property Value
Default level ignore
Message @ must not be used stand alone
Options none

Discourages using @ on its own as a synonym for this (see CoffeeScript issue #1601).

# Allowed
@name
@[key]
@()
@::method

# Reported
self = @
register(@)

no_this

Property Value
Default level ignore
Message Don't use 'this', use '@' instead
Options none

Forbids the this keyword in favor of @:

this.name = name   # Bad
@name = name       # Good

This rule cooperates with no_stand_alone_at: when that rule is active, a bare this (not followed by a dot) is allowed, because replacing it with a bare @ would violate the other rule. In that setup, this.name is still reported but self = this is not.

no_unnecessary_double_quotes

Property Value
Default level ignore
Message Unnecessary double quotes are forbidden
Options none

Requires single quotes unless double quotes are needed:

# Discouraged
foo = "bar"

# Allowed: interpolation
foo = "#{bar}baz"

# Allowed: avoids escaping single quotes
foo = "I'm just following the 'rules'"

non_empty_constructor_needs_parens

Property Value
Default level ignore
Message Invoking a constructor without parens and with arguments
Options none

Requires parentheses when calling a constructor with arguments:

p = new Point(1, 2)   # Good
p = new Point 1, 2    # Bad

prefer_english_operator

Property Value
Default level ignore
Message Don't use &&, ||, ==, !=, or !
Options doubleNotLevel (default ignore)

Prefers CoffeeScript's English operators. Each finding comes with a suggestion in its context:

Found Suggestion
== Replace "==" with "is"
!= Replace "!=" with "isnt"
|| Replace "||" with "or"
&& Replace "&&" with "and"
! Replace "!" with "not"
!! "?" is usually better than "!!"

The double negation !!value (a common way to coerce to a boolean) is governed separately by doubleNotLevel, which is ignore by default. Set it to warn or error to report it too:

{
  "prefer_english_operator": {
    "level": "error",
    "doubleNotLevel": "warn"
  }
}

See Also