Skip to content

Latest commit

 

History

History
4249 lines (4142 loc) · 76.1 KB

Specs.md

File metadata and controls

4249 lines (4142 loc) · 76.1 KB

Arrays

Empty array
var a = []
a = []
Multiple items
var a = [ 1, 2, 3, 4 ]
a = [
  1
  2
  3
  4
]

Comments

After block comment
function x() {
  return y;
  /*
   * hello
   */
}
x = ->
  y

hello

Block comments
a();
/*
 * hello
 */
b();
a()

hello

b()

Block comments in blocks
if (x) {
  /*
   * hello
   * world
   */
  y();
}
if x

hello

world

y()

Block comments with space
a(); /* hi */
b();
a()

hi

b()

Comment before function
a()
/*
 * comment
 */
function x() {
  return;
}
###
# comment
###

x = -> return

a()

Comments in if blocks
if (true) {
  // yes
} else {
  // no
}
if true
  # yes
else
  # no
Indented jsdoc comments
if (x) {
  /**
   * documentation here
   */
  y();
}
if x

###*

documentation here

y()

Line comments
a();
// hello
b();
a()
# hello
b()
Line comments before function
a()
// one
// two
// three
function x() {
  return;
}
# one
# two
# three

x = -> return

a()

Multiple functions with multiple comments
a()
// one
// two
// three
function x() {
  return;
}
// four
// five
// six
function y() {
  return;
}
# one
# two
# three

x = -> return

four

five

six

y = -> return

a()

Program block comment after
a();
/*
 * hello
 */
a()

hello

Program block comment before
/*
 * hello
 */
a();
###
# hello
###

a()

Program block comment sole
/*
 * hello
 */
###
# hello
###
Program with only comments
// hi
// there
/* world */
# hi
# there

world

Sole block comment
function fn() {
  /*
   * hello
   */
}
fn = ->

hello

return

Trailing line comment
hello(); // there
world();
hello()
# there
world()

Compatibility mode

Assignment of reserved words
on = 2
`on = 2`
Assignment of reserved words off
on = 2
Error:
/'on' is a reserved CoffeeScript keyword/
Empty array slots
[, 0]
`[
  ,
  0
]`
Empty array slots off
[, 0]
Error:
/Empty array slots are not supported in CoffeeScript/
Equals
if (a == b(c + 2)) { run(); }
if `a == b(c + 2)`
  run()
Equals off
if (a == b(c + 2)) { run(); }
if a == b(c + 2)
  run()
Named function expressions
var x = function fn() {
  return fn;
}
x = (`function fn() {
  return fn;
}`)
Named function expressions off
var x = function fn() {
  return fn;
};
alert(typeof x())
x = ->
  fn

alert typeof x()

Undefined
undefined
`undefined`
Undefined off
undefined
undefined

Default params

Mixed params
function greet(greeting, name = 'Bob') {
  return name;
}
greet = (greeting, name = 'Bob') ->
  name
Mixed params 2
function greet(name = 'Bob', age) {
  return name;
}
greet = (name = 'Bob', age) ->
  name
With defaults
function greet(name = 'Bob') {
  return name;
}
greet = (name = 'Bob') ->
  name
With non literal defaults
function fn(param = (a + b())) {
  return true
}
fn = (param = a + b()) ->
  true

Errors

Breakless switch
switch (x) {
  case 1:
    b();
  case 2:
    c();
}
Error:
/No break or return statement found/
Reserved keyword
off = 2
Error:
/'off' is a reserved CoffeeScript keyword/
Reserved keyword in params
function x(off) {}
Error:
/'off' is a reserved CoffeeScript keyword/
Reserved keyword in var
var off = 2
Error:
/'off' is a reserved CoffeeScript keyword/
Switch default cases
switch (x) {
  default:
    a();
  case b:
    c();
    break;
}
Error:
/default cases only allowed at the end/
With
with (x) { a(); }
Error:
/'with' is not supported/

Function calls

Call with function expression
run(function () {
  a();
  b();
  return;
});
run ->
  a()
  b()
  return
Call with function indented
if (x) {
  setTimeout(function() { return go(); }, 300)
}
if x
  setTimeout (->
    go()
  ), 300
Call with function then object
box.on('click', function () {
  return go();
}, { delay: 500, silent: true })
box.on 'click', (->
  go()
),
  delay: 500
  silent: true
Call with multiple objects
a({ one: 1 }, { two: 2 })
a { one: 1 }, two: 2
Call with object
box.on('click', { silent: true }, function () {
  return go();
})
box.on 'click', { silent: true }, ->
  go()
Call with param after function
setTimeout(function () {
  return work();
}, 500);
setTimeout (->
  work()
), 500
Chaining
get().then(function () {
  return a();
}).then(function () {
  return b();
});
get().then(->
  a()
).then ->
  b()
Expression with call
(function () {
  return go();
}).call(this);
(->
  go()
).call this
Iife with different argument names
(function($) {
  go();
  return;
})(jQuery);
(($) ->
  go()
  return
) jQuery

Functions

Dont unpack returns in incomplete ifs
function a() {
  if (x)
    return b();
  else
    c();
}
a = ->
  if x
    return b()
  else
    c()
  return
Function reordering
alert(name());
if (ok) {
  a();
  function name() {
    return "John";
  }
}
name = ->
  'John'

alert name() if ok a()

Functions after var
function fn() {
  var x;
  function fn2() {
    return x = 2;
  }
}
fn = ->
  x = undefined

fn2 = -> x = 2

return

Functions in ternaries
_.propertyOf = function(obj) {
  return obj === null ? (x && function(){}) : function(key) {
    return obj[key];
  };
};
_.propertyOf = (obj) ->
  if obj == null then x and (->
  ) else ((key) ->
    obj[key]
  )
Multiple declarations
function one() {
  return a();
}
function two() {
  return b();
}
one = ->
  a()

two = -> b()

Multiple expressions
obj.one = function () {
  return a();
};
obj.two = function () {
  return b();
};
obj.one = ->
  a()

obj.two = -> b()

Named function expressions
var x = function fn() {
  return fn;
}
x = ->
  fn
Nested declarations
function a () {
  function b () {
    return c;
  }
}
a = ->

b = -> c

return

Nested functions in object
({
  a: function () {
    function b() { return c; }
    return b()
  }
})
a: ->

b = -> c

b()

Prevent implicit returns
function a() {
  b();
}
a = ->
  b()
  return
Return object
function fn() {
  if (x)
    return { a: 1, b: 2 };
  return true;
}
fn = ->
  if x
    return {
      a: 1
      b: 2
    }
  true
Return statement
function a () {
  if (x) return b;
  return c;
}
a = ->
  if x
    return b
  c
Undefined in function expression parameters
call(function (undefined) {
  return true;
});
call ->
  true
Undefined in parameters
function fn (undefined) {
  return true;
}
fn = ->
  true
Unpacking returns
function a() {
  return b;
}
a = ->
  b
Unpacking returns in ifs
function a() {
  if (x)
    return b();
  else
    return c();
}
a = ->
  if x
    b()
  else
    c()
Unpacking returns in ifs with elses
function a() {
  if (x)
    return b();
  else if (y)
    return c();
  else
    return d();
}
a = ->
  if x
    b()
  else if y
    c()
  else
    d()
Unpacking returns in nested ifs
function returns() {
  if (x) {
    if (y) {
      return y
    } else {
      return x
    }
  } else {
    return z
  }
}
returns = ->
  if x
    if y
      y
    else
      x
  else
    z
With arguments
function a(b, c) { d(); }
a = (b, c) ->
  d()
  return

Globals

Global assignment
function fn () {
  a = 2;
  return;
}
fn = ->
  a = 2
  return
Global assignment compat
function fn () {
  a = 2;
  return;
}
fn = ->
  `a = 2`
  return
In function params
function fn(x) {
  x = 2;
  return
}
fn = (x) ->
  x = 2
  return

If

Blank ifs
if (condition) {}
if condition
else
Blank ifs with comments
if (condition) {
  // pass
}
if condition
  # pass
else
Else if
if (a) {
  x();
} else if (b) {
  y();
} else {
  z();
}
if a
  x()
else if b
  y()
else
  z()
Escaping if functions
if (a === function(){ return x(); }) {
  b()
  c()
}
if a == (->
    x()
  )
  b()
  c()
Escaping if functions with indent
if (1) {
  if (2) {
    if (3) {
      if (a === function(){ return x(); }) {
        b()
        c()
      }
    }
  }
}
if 1
  if 2
    if 3
      if a == (->
          x()
        )
        b()
        c()
If blocks
if (a) {
  b();
  c();
  d();
}
if a
  b()
  c()
  d()
If statement
if (a) b()
if a
  b()
If with else
if (a) { b(); }
else { c(); }
if a
  b()
else
  c()
If with else if inside functions
function fn() {
  if (a) { b(); }
  else if (b) { c(); }
  else { d(); }
  return;
}
fn = ->
  if a
    b()
  else if b
    c()
  else
    d()
  return
If with else inside functions
function fn() {
  if (a) { b(); } else { c(); }
  return;
}
fn = ->
  if a
    b()
  else
    c()
  return
If with nesting
if (a) {
  if (b) {
    c();
  }
}
if a
  if b
    c()
Multiple else ifs
if (a) {
  x();
} else if (b) {
  y();
} else if (b) {
  y();
} else if (b) {
  y();
} else if (b) {
  y();
} else {
  z();
}
if a
  x()
else if b
  y()
else if b
  y()
else if b
  y()
else if b
  y()
else
  z()
Non block consequents
function fn() {
  if (a) b();
  else c();
  return;
}
fn = ->
  if a
    b()
  else
    c()
  return
Ternary in if
if (a ? b : c) { d(); }
if (if a then b else c)
  d()
Ternary in if and binary
if (x && (a ? b : c)) { d(); }
if x and (if a then b else c)
  d()

Iife

Iife
(function(){ return true; })()
do ->
  true
Iife as an expression
$((function() { return true; })())
$ do ->
  true
Iife with arguments
(function(jQuery){ return true; })(jQuery)
do (jQuery) ->
  true
Iife with multiple arguments
(function(jQuery, window){ return true; })(jQuery, window)
do (jQuery, window) ->
  true
Iife with non matching arguments
(function () {
  return true
})(a);
(->
  true
) a
Iife with non matching literal arguments
(function () {
  return true
})(2);
(->
  true
) 2

Indent

Spaces 4
if (condition) {
  consequent();
}
if condition
    consequent()
Spaces 8
if (condition) {
  consequent();
}
if condition
        consequent()
Tab
if (condition) {
  consequent();
}
if condition
	consequent()

Legacy

Anon invocation
(function ($) { return $; }(jQuery));
(function ($) { return $; }());
(($) ->
  $
) jQuery
(($) ->
  $
)()
Array literals
var arr1 = [];
var arr2 = [1,3,4];
console.log(arr2[1][0] + [4]);
arr1 = []
arr2 = [
  1
  3
  4
]
console.log arr2[1][0] + [ 4 ]
Assign
a = 2;
a += 1;
a -= 1;
a *= 4;
a /= 2;
a %= 0;
a <<= 0;
a ^= 0;
a = 2
a += 1
a -= 1
a *= 4
a /= 2
a %= 0
a <<= 0
a ^= 0
Bitwise shift
var value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16);
value = (value & 255) << 16 | value & 65280 | (value & 16711680) >>> 16
Blank lines
x = 2

y = 3

x = 2
y = 3
Block comments
/**
API documentation
*/
###*
API documentation
###
Call statement
function x() {
  alert(2+2);
  alert(y(10));
}

$.get({ ajax: true, url: 'foo' });

x = ->
  alert 2 + 2
  alert y(10)
  return

$.get ajax: true url: 'foo'

Crlf
var x = 3
var y = 2
x = 3
y = 2
Debugger
debugger;
debugger
Delete
delete a[x];
delete a[x]
Do
var i = 0;
do {
  console.log(i);
  i++;
} while (i < 14);
i = 0
loop
  console.log i
  i++
  unless i < 14
    break
Dont unreserve property accessors
io.on('data', function() { console.log('Received'); });
this.on('data', function() { console.log('Received'); });
io.on 'data', ->
  console.log 'Received'
  return
@on 'data', ->
  console.log 'Received'
  return
Empty function
(function($) {})()
(($) ->
)()
Empty function bodies
x = { v: function() { return 2; }, y: function(){}, z: function(){} };
x =
  v: ->
    2
  y: ->
  z: ->
Empty semicolon
2;;;3
2
3
Equal regex
var re = /=/;
console.log("a = b".match(re));
re = RegExp('=')
console.log 'a = b'.match(re)
Floating point numbers
0.094;
91;
9;
0;
-1;
-20.89889;
-424;
482934.00000001;
0.094
91
9
0
-1
-20.89889
-424
482934.00000001
For
for (x=0; !x<2; x++) { alert(1) }
for (; !x<2; ) { alert(1) }
for (;;++x) { alert(1) }
for (;;) { alert(1) }
x = 0
while !x < 2
  alert 1
  x++
while !x < 2
  alert 1
loop
  alert 1
  ++x
loop
  alert 1
For in
for (var x in y) { alert(1) }
for (var key in obj) {}
for (key in obj)
    single_liner()
for x of y
  alert 1
for key of obj
  continue
for key of obj
  single_liner()
Function order
var x = function() {
    alert(y());
    var z = function() { return 3; }
    function y() { return 2; }
}
x = ->

y = -> 2

alert y()

z = -> 3

return

Function property
(function (){}.apa);
var f = function(){}.bind(this);
(->
).apa
f = (->
).bind(this)
Function with keyword
function x() {}
x = ->
If in
if (key in obj)
    single_liner()
if key of obj
  single_liner()
Increment decrement
a++;
++a;
--a;
a--;
a+++a;
a---a;
a++
++a
--a
a--
a++ + a
a-- - a
Index
a[x] = 2
a[x] = 2
Numbers
var x = 1e3;
x = 1e3
Or
var a = 2 || {}
a = 2 or {}
Parenthesized new
(new Date).getTime()
(new Date).getTime()
Return function
(function() { return function() { return 2 }; })
->
  ->
    2
Simple addition
var a = 8+2+2;2
a = 8 + 2 + 2
2
Single line else
if ((x !== 2) && (2)) { 2;2 } else true
if x != 2 and 2
  2
  2
else
  true
Single return
(function() { return; });
->
  return
Switch
switch (x) { case 2: a; break; case 3: b; break; default: x; }
switch (x) { case 2: case 3: b; break; default: x; }
switch x
  when 2
    a
  when 3
    b
  else
    x
switch x
  when 2, 3
    b
  else
    x
Ternary
a?b:c
if a then b else c
This attribute
(function() {
  return this.foo;
})

->
  @foo
This keyword
(function() {
  return this;
})

->
  this
Throw
try {
throw 2;} catch(x) { alert (x); }
try
  throw 2
catch x
  alert x
Unary
-1;
+1;
+1 - 1;
+1 -1;
~2 - 2;
~2+-1;
var a =~ 2;
-1
+1
+1 - 1
+1 - 1
~2 - 2
~2 + -1
a = ~2
Var
var x = 2;
var y;
var f = function() { return y };
x = 2
y = undefined

f = -> y

Loops

Continue statement
while (condition) {
  if (x) continue;
  a();
}
while condition
  if x
    continue
  a()
Do while
do {
  b();
} while (a)
loop
  b()
  unless a
    break
Do while with other statements
function fn() {
  before();
  do {
    b();
  } while (a);
  after();
  return;
}
fn = ->
  before()
  loop
    b()
    unless a
      break
  after()
  return
Empty while
while (a) {}
while a
  continue
For in with if
if (condition) {
  for (var a in b) if (c) d();
}
if condition
  for a of b
    if c
      d()
For in with var
for (var x in y) {
  z();
}
for x of y
  z()
For with continue
for (a; b; update++) {
  if (x) continue;
  d()
}
a
while b
  if x
    update++
    continue
  d()
  update++
For with continue with switch
for (a; b; update++) {
  switch (x) {
    case 1:
      continue;
      break;
  }
  d()
}
a
while b
  switch x
    when 1
      update++
      continue
  d()
  update++
For with continue without init
for (;;c++) {
  if (true) continue;
  if (false) continue;
}
loop
  if true
    c++
    continue
  if false
    c++
    continue
  c++
For with if
if (condition)
  for (a;b;c) if (d) e();
if condition
  a
  while b
    if d
      e()
    c
For with no arguments
for (;;) {
  d();
}
loop
  d()
For with no body
for(;;){}
loop
  continue
For with no init
for (;b;c) {
  d();
}
while b
  d()
  c
For with no test
for (a;;c) {
  d();
}
a
loop
  d()
  c
For with no update
for (a;b;) {
  d();
}
a
while b
  d()
Forever loop
while (true) {
  a();
}
loop
  a()
Indented for
if (true) {
  for (a;b;c) { d; }
}
if true
  a
  while b
    d
    c
Simple for
for (a;b;c) {
  d();
}
a
while b
  d()
  c
While
while (condition) { a(); }
while condition
  a()
While with break
while (condition) {
  if (x) break;
  a();
}
while condition
  if x
    break
  a()
While with no body
if (true) {
  while (a) {
  }
}
if true
  while a
    continue

Members

Identifier in brackets
a[x]
a[x]
Identifiers
a.b
a.b
Prototype
a.prototype.b = {};
a.prototype;
a::b = {}
a.prototype
This prototype
this.prototype.a = 1;
@::a = 1

New

New operator
var a = new B
a = new B
New operator with arguments
var a = new B(x,y);
a = new B(x, y)
New with complex callee
var a = new (require('foo'))(b)
a = new (require('foo'))(b)
New with function expression
var a = new MyClass('left', function () {
  go();
  return;
})
a = new MyClass('left', ->
  go()
  return
)
New with function expression and string
var a = new MyClass(function () {
  go();
  return;
}, 'left')
a = new MyClass((->
  go()
  return
), 'left')

Objects

Arrray of objects
var list = [
  { a: 1, b: 1 },
  { a: 2, b: 2 },
]
list = [
  {
    a: 1
    b: 1
  }
  {
    a: 2
    b: 2
  }
]
Call with object
call({ a: 1, b: 2 })
call
  a: 1
  b: 2
Multiple object expressions
({ a: 1, b: 2 });
({ c: 3, d: 4 });
{
  a: 1
  b: 2
}
c: 3
d: 4
Multiple properties
a = { b: 2, c: 3 }
a =
  b: 2
  c: 3
Nested objects
a = { b: { x: 3, y: 3 }, d: 4 }
a =
  b:
    x: 3
    y: 3
  d: 4
Nesting into a single line
var x = ({a: {b: {c: {d: e}}, f: {g: {h: i}}}})
x = a:
  b: c: d: e
  f: g: h: i
Object with arrays
a = {
  empty: [],
  one: [ 1 ],
  many: [ 1, 2, 3 ]
};
a =
  empty: []
  one: [ 1 ]
  many: [
    1
    2
    3
  ]
Simple object
var a = { b: 2 }
a = b: 2
Single object expression
({ a: 1, b: 2 })
a: 1
b: 2
Singleton with methods
App = {
  start: function () { go(); return; },
  stop: function () { halt(); return; }
}
App =
  start: ->
    go()
    return
  stop: ->
    halt()
    return
Unusual identifiers
object = {
    a: b,
    "a.a": b,
    "a#a": b,
    "a a": b,
    0: b,
    "0.a": b,
    $: b,
    $$: b,
    $a: b,
    "$a b": b
};
object =
  a: b
  'a.a': b
  'a#a': b
  'a a': b
  0: b
  '0.a': b
  $: b
  $$: b
  $a: b
  '$a b': b

Precedence

Addition and multiplication
(a + b) * c
(a + b) * c
Binary expressions
a | b ^ c & d
a | b ^ c & d
Binary expressions with parens
((a | b) ^ c) & d
((a | b) ^ c) & d
Call expression
a.b()
a.b()
Instanceof and function call
(a instanceof b)(c)
(a instanceof b) c
Intransitive operations division
a/b/c;

(a/b)/c; (a*b)/c; (a/b)c; (ab)*c;

a/(b/c); a/(bc); a(b/c); a*(b*c);

a / b / c
a / b / c
a * b / c
a / b * c
a * b * c
a / (b / c)
a / (b * c)
a * b / c
a * b * c
Intransitive operations subtraction
a-b-c;

(a-b)-c; (a+b)-c; (a-b)+c; (a+b)+c;

a-(b-c); a-(b+c); a+(b-c); a+(b+c);

a - b - c
a - b - c
a + b - c
a - b + c
a + b + c
a - (b - c)
a - (b + c)
a + b - c
a + b + c
Logical operators
(a || b) && (c || d)
(a or b) and (c or d)
Nested new
new X(new Y)
new X(new Y)
Nested ternary
a ? b : c ? d : e
if a then b else if c then d else e
Nested ternary 2
a ? b ? c : d : e
if a then (if b then c else d) else e
Parenthesized classname in new
new (X())
new (X())
Strip useless parens
(a + b) + c + (d + e)
a + b + c + d + e
Ternary and assignment
a ? (b=c) : d
if a then (b = c) else d
Typeof and member expression
(typeof x)[2]
(typeof x)[2]

Regexp

Blank with flag
/ /g
RegExp ' ', 'g'
Equals
a(/=\s/)
a RegExp('=\\s')
Equals with flag
/=/g
RegExp '=', 'g'

Shadowing

Var shadowing
var val = 2;
var fn = function () {
  var val = 1;
  return;
}
fn();
assert(val === 2);
val = 2

fn = -> var val val = 1 return

fn() assert val == 2

Simple

Array newlines
controller('name', [
  'a',
  'b',
  function (a, b) {
    alert('ok');
    return;
  },
  'z'
]);
controller 'name', [
  'a'
  'b'
  (a, b) ->
    alert 'ok'
    return
  'z'
]
Binary operators
a << b;
a >> b;
a | b;
a ^ b;
a & b;
a ^ b & c | d;
a << b
a >> b
a | b
a ^ b
a & b
a ^ b & c | d
Booleans
true;
false;
true
false
Call with function
a(function() {
  b();
  return;
});
a ->
  b()
  return
Debugger statement
if (x) debugger;
if x
  debugger
Delete
delete x.y;
delete x.y
Empty statement
;;
Empty statement with other statements
a();;;b()
a()
b()
Exponents
Math.pow(2, 8)
2 ** 8
Exponents precedence
Math.pow(1 * 2, 8)
Math.pow(!x, 8)
Math.pow(x++, 8)
Math.pow(++y, 8)
Math.pow(new X, 8)
Math.pow(new X(2), 8)
Math.pow(a < b, 8)
(1 * 2) ** 8
(!x) ** 8
x++ ** 8
++y ** 8
new X ** 8
new X(2) ** 8
(a < b) ** 8
Exponents with strange arguments
var a = Math.pow(2)
a = Math.pow(2)
Function call
alert("Hello world");
alert 'Hello world'
Function call with arguments
a("hello", 2);
a 'hello', 2
Function in switch
for(var i = 0; i <5; ++i) {
   switch(i) {
     case 1:
       function foo() { return 2; }
       alert("one");
       break;
   }
}
foo = ->
  2

i = 0 while i < 5 switch i when 1 alert 'one' ++i

Increment
a++
b--
a++
b--
Indentation of parentheses
if (w) {
  x(y(function() {
    return true
  }));
  z()
}
if w
  x y(->
    true
  )
  z()
Indented throw
if (x) throw e
if x
  throw e
Index resolution
a[2]
a[2]
Index resolution of expression
a["node" + n]
a['node' + n]
Index resolution of strings
a["a-b"]
a['a-b']
Index resolution with this
this["#" + id]
@['#' + id]
Inline assignment
var a, m;
if (a = m = match) {
  m();
}
a = undefined
m = undefined
if a = m = match
  m()
Logical expressions
a || b;
c && d;
a or b
c and d
Multiple unary operators
0 + - + - - 1
0 + - + - -1
Nested function calls
a(b(c(d())));
a b(c(d()))
Nesting if and assignment
a.b = function (arg) {
  if (arg) cli.a = b;
  return;
};
a.b = (arg) ->
  if arg
    cli.a = b
  return
Null check
function ifNullChecks() {
  if (x===null) { yep() }
  return
}
ifNullChecks = ->
  if x == null
    yep()
  return
Prefix increment
++a;
--b;
++a
--b
Prototype
a.prototype.b = 1
a.prototype = {}
a::b = 1
a.prototype = {}
Recursing into new functions
var a = x ? y : function () {
  return a === "b";
};
a = if x then y else (->
  a == 'b'
)
Return nothing
function fn () {
  return;
}
fn = ->
  return
Scientific notation
var a = -1.21e3;
a = -1.21e3
Sequence expression
a,b,c
a
b
c
Sequence expression with indent
if (x) {
  a,b,c;
}
if x
  a
  b
  c
Standalone this
var a = this;
a = this
Ternary operator
a ? b : c
if a then b else c
Ternary operator nesting
a ? b : c ? d : e
if a then b else if c then d else e
This prefix
this.run(this);
@run this
Throw
throw e
throw e
Void 0
void 0
undefined

Spacing

Block comments
/*
 * hello
 */
there();
/*
 * world
 */
###
# hello
###

there()

world

Collapsing extra newlines
/*
 * hello
 */
/*
 * world
 */
###
# hello
###

world

Special cases

Assignment in condition
var options;
if ( (options = arguments[ i ]) !== null ) {
  for (var x in y) { z(); }
}
options = undefined
if (options = arguments[i]) != null
  for x of y
    z()
Unary and object expression
+{ a: '2' }
+{ a: '2' }
Unary and object with call
!{ toString: null }.propertyIsEnumerable('string')
!{ toString: null }.propertyIsEnumerable('string')

Strings

Empty string
""
''
Prevent interpolation
"#{a}"
'#{a}'
Simple string
"hello"
'hello'
Single quotes
'\n'
'\n'
String with escapes
"\n"
'\n'
Unicode
'\u2028'
'\u2029'
'\u2028'
'\u2029'

Switch

Case consolidation
switch (a) {
  case one:
  case two:
    b();
    break;
  default:
    c();
}
switch a
  when one, two
    b()
  else
    c()
Case consolidation with default
switch (a) {
  case one:
    b();
    break;
  case two:
  default:
    c();
}
switch a
  when one
    b()
  else
    c()
Switch
switch (obj) {
  case 'one':
    a();
    break;
  case 'two':
    b();
    break;
  default:
    c();
}
switch obj
  when 'one'
    a()
  when 'two'
    b()
  else
    c()
Switch with comments
switch (obj) {
  // test
  case 'one':
    // test
    a();
    break;
  // test
  case 'two':
    // test
    b();
    break;
  default:
    c();
}
switch obj
  # test
  when 'one'
    # test
    a()
  # test
  when 'two'
    # test
    b()
  else
    c()
Switch with conditional expression
switch (a?b:c) {
  case d:
    e();
    break;
}
switch (if a then b else c)
  when d
    e()
Switch with continue
while (true) {
  switch (x) {
    case 1:
      continue;
  }
}
loop
  switch x
    when 1
      continue
Switch with return
function fn () {
  switch (obj) {
    case 'one':
      return a();
    default:
      return b();
  }
  return
}
fn = ->
  switch obj
    when 'one'
      return a()
    else
      return b()
  return

Try

No finally
try {
  a();
} catch (e) {
  b();
}
try
  a()
catch e
  b()
Try catch finally
try {
  a();
} catch (e) {
  b();
} finally {
  c();
}
try
  a()
catch e
  b()
finally
  c()
Try with indent
if (x) {
  try { a(); }
  catch (e) { b(); }
  finally { c(); }
}
if x
  try
    a()
  catch e
    b()
  finally
    c()

Var

Mixed var declarations
if (true) {
  var a = 1, b, c = 2, d;
}
if true
  a = 1
  b = undefined
  c = 2
  d = undefined
Multiple var declaration
var a = 1, b = 2
a = 1
b = 2
Multiple var declarations with indent
if (true) {
  var a = 1, b = 2;
}
if true
  a = 1
  b = 2
Var declaration
var a = 1
a = 1
Var without initializer
var a;
a = undefined

Warnings

Equals
a == b
a == b
For in without var
for (x in y) { z }
for x of y
  `x = x`
  z
Shadowing
function add () { var add = 2; return }
add = ->
  `var add`
  add = 2
  return