Automatic Semicolon Insertion

Article by Garrett Smith

This document is an addendum to Code Guidelines for Rich Internet Application Development.

Unrestricted Productions

Productions that are not restricted can be created accidentally where ASI has been used. This is often the result of where the developer forgot to use a semicolon. Regardless, the problems it creates can occur when the order of Statements changes or when line terminators are added or removed, including those that appear in comments. Where semicolons are needed, it is recommended that they appear explicitly.

Grouping Operator or Arguments?

The parentheses following an Expression interpreted as Arguments, implicating the Expression in a CallExpression:

var MyWidget = function(){
 this.name = "mike";
}
/**
  * Initialize Widget
  */
(function() {
  /*...*/
});

The FunctionExpression that appears on the right hand side of the assignment to the identifier MyWidget would be called because the parentheses, which were intended to be a Grouping Operator, are interpreted as Arguments in a CallExpression, resulting in MyWidget having the value undefined and window.name getting the value "mike".

This can be explained by the fact that a program is scanned from left to right, repeatedly taking the longest possible sequence of characters as the next input element. Since a CallExpression is not a restricted production, the program would be interpreted as:

var MyWidget = function(){
 this.name = "mike";
}(function() {});

ArrayLiteral or Property Accessor?

An ArrayLiteral can be interpreted as property accessor after the removal of a restricted production. In this case, Expression g--.

var g = 12
g--
[].slice.call([1,2,3])

The program is interpreted as:

var g = 12;
g--;
[].slice.call([1,2,3])

When the postfix operator is removed, a SyntaxError results. Given the input:

var g = 12
--g
[].slice.call([1,2,3])

The program is interpreted as:-

var g = 12;
--g[].slice.call([1,2,3])

- and that program is not valid syntax so it results in a SyntaxError.

Line Terminators in Comments

A LineTerminator in any MultilineComment affects ASI. From ECMAScript Edition 5 specification, 5.1.2:

A MultiLineComment (that is, a comment of the form /*...*/ regardless of whether it spans more than one line) is likewise simply discarded if it contains no line terminator; but if a MultiLineComment contains one or more line terminators, then it is replaced by a single line terminator, which becomes part of the stream of input elements for the syntactic grammar.

Not all implementations follow rules of whitespace in MultiLineComment. JScript is one such implementation that does not process a MultiLineComment that contains a LineTerminator as a LineTerminator.

A program that uses semicolons explicitly avoids such problems and is less susceptible to behavior changes (including script errors) caused by inadvertent changes in line terminators and expressions, including those introduced by build tools (e.g. minficication).