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
- empty_constructor_needs_parens
- ensure_comprehensions
- no_backticks
- no_empty_param_list
- no_implicit_braces
- no_implicit_parens
- no_interpolation_in_single_quotes
- no_nested_string_interpolation
- no_plusplus
- no_stand_alone_at
- no_this
- no_unnecessary_double_quotes
- non_empty_constructor_needs_parens
- prefer_english_operator
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
forloops 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
- Rules Overview for the complete list.
- Configuration for setting levels and options.