From e15af4c84993ef730e1c07168f7cc97bc027f304 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Tue, 7 Apr 2015 21:51:50 -0500
Subject: [PATCH 01/17] Add require.js error reporting in tests

Adds test coverage for #989
---
 spec/amd-runtime.html | 16 ++++++++++++++++
 spec/amd.html         | 23 +++++++++++++++++++----
 2 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/spec/amd-runtime.html b/spec/amd-runtime.html
index 19bccdbf5..7cc64f190 100644
--- a/spec/amd-runtime.html
+++ b/spec/amd-runtime.html
@@ -28,11 +28,16 @@
 
     <script src="/spec/env/common.js"></script>
     <script>
+      var requireFailure;
+
       requirejs.config({
         paths: {
           'handlebars.runtime': '/dist/handlebars.runtime.amd'
         }
       });
+      requirejs.onError = function (err) {
+        requireFailure = err;
+      };
     </script>
     <script>
       onload = function(){
@@ -60,6 +65,17 @@
 
           runner.on('fail', logFailure);
 
+          // Inject any require initilizer failures into the first test so they are properly
+          // reported.
+          if (requireFailure) {
+            runner.on('hook end', function(hook){
+              if (requireFailure) {
+                runner.uncaught(requireFailure);
+                requireFailure = undefined;
+              }
+            });
+          }
+
           function logFailure(test, err){
 
             var flattenTitles = function(test){
diff --git a/spec/amd.html b/spec/amd.html
index 864ee8315..5de33c1cf 100644
--- a/spec/amd.html
+++ b/spec/amd.html
@@ -28,12 +28,17 @@
 
     <script src="/spec/env/common.js"></script>
     <script>
+      var requireFailure;
+
       requirejs.config({
         paths: {
           handlebars: '/dist/handlebars.amd',
           tests: '/tmp/tests'
         }
       });
+      requirejs.onError = function (err) {
+        requireFailure = err;
+      };
 
       var CompilerContext = {
         compile: function(template, options) {
@@ -79,16 +84,26 @@
 
             runner.on('fail', logFailure);
 
-            function logFailure(test, err){
+            // Inject any require initilizer failures into the first test so they are properly
+            // reported.
+            if (requireFailure) {
+              runner.on('hook end', function(hook){
+                if (requireFailure) {
+                  runner.uncaught(requireFailure);
+                  requireFailure = undefined;
+                }
+              });
+            }
 
-              var flattenTitles = function(test){
+            function logFailure(test, err){
+              function flattenTitles(test){
                 var titles = [];
                 while (test.parent.title){
                   titles.push(test.parent.title);
                   test = test.parent;
                 }
                 return titles.reverse();
-              };
+              }
 
               failedTests.push({
                 name: test.title,
@@ -97,7 +112,7 @@
                 stack: err.stack,
                 titles: flattenTitles(test)
               });
-            };
+            }
           });
         });
       };

From 81a4d50955b13e7d5e5052d904bb3e8c993ebb88 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Tue, 7 Apr 2015 22:35:14 -0500
Subject: [PATCH 02/17] Avoid source-map import under AMD

Fixes #989
---
 lib/handlebars/compiler/code-gen.js | 14 ++++++++++++--
 spec/source-map.js                  |  6 ++++--
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/lib/handlebars/compiler/code-gen.js b/lib/handlebars/compiler/code-gen.js
index 0fddb7c65..e99809587 100644
--- a/lib/handlebars/compiler/code-gen.js
+++ b/lib/handlebars/compiler/code-gen.js
@@ -1,9 +1,19 @@
 import {isArray} from "../utils";
 
+var SourceNode;
+
 try {
-  var SourceMap = require('source-map'),
-        SourceNode = SourceMap.SourceNode;
+  if (typeof define !== 'function' || !define.amd) {
+    // We don't support this in AMD environments. For these environments, we asusme that
+    // they are running on the browser and thus have no need for the source-map library.
+    var SourceMap = require('source-map');
+    SourceNode = SourceMap.SourceNode;
+  }
 } catch (err) {
+  /* NOP */
+}
+
+if (!SourceNode) {
   /* istanbul ignore next: tested but not covered in istanbul due to dist build  */
   SourceNode = function(line, column, srcFile, chunks) {
     this.src = '';
diff --git a/spec/source-map.js b/spec/source-map.js
index 6eced9ca0..8037b88c2 100644
--- a/spec/source-map.js
+++ b/spec/source-map.js
@@ -1,7 +1,9 @@
 /*global CompilerContext, Handlebars */
 try {
-  var SourceMap = require('source-map'),
-        SourceMapConsumer = SourceMap.SourceMapConsumer;
+  if (typeof define !== 'function' || !define.amd) {
+    var SourceMap = require('source-map'),
+          SourceMapConsumer = SourceMap.SourceMapConsumer;
+  }
 } catch (err) {
   /* NOP for in browser */
 }

From 2d149e779764cb373be0585c5e493da405062be6 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Tue, 7 Apr 2015 23:37:38 -0500
Subject: [PATCH 03/17] Add undefined and null literal support

This adds the UndefinedLiteral and NullLiteral to AST.

Fixes #990
---
 docs/compiler-api.md                |  8 ++++++++
 lib/handlebars/compiler/ast.js      | 12 ++++++++++++
 lib/handlebars/compiler/compiler.js |  8 ++++++++
 lib/handlebars/compiler/printer.js  |  8 ++++++++
 lib/handlebars/compiler/visitor.js  |  2 ++
 spec/basic.js                       | 10 ++++++++++
 spec/javascript-compiler.js         |  2 +-
 spec/parser.js                      |  4 ++++
 spec/tokenizer.js                   |  7 +++++++
 spec/visitor.js                     |  2 +-
 src/handlebars.l                    |  2 ++
 src/handlebars.yy                   |  2 ++
 12 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/docs/compiler-api.md b/docs/compiler-api.md
index 40ded8fd2..c09414f0b 100644
--- a/docs/compiler-api.md
+++ b/docs/compiler-api.md
@@ -164,6 +164,14 @@ interface NumberLiteral <: Literal {
     value: number;
     original: number;
 }
+
+interface UndefinedLiteral <: Literal {
+    type: "UndefinedLiteral";
+}
+
+interface NullLiteral <: Literal {
+    type: "NullLiteral";
+}
 ```
 
 
diff --git a/lib/handlebars/compiler/ast.js b/lib/handlebars/compiler/ast.js
index 45212b383..e5904c659 100644
--- a/lib/handlebars/compiler/ast.js
+++ b/lib/handlebars/compiler/ast.js
@@ -101,6 +101,18 @@ var AST = {
       this.value = bool === 'true';
   },
 
+  UndefinedLiteral: function(locInfo) {
+    this.loc = locInfo;
+    this.type = 'UndefinedLiteral';
+    this.original = this.value = undefined;
+  },
+
+  NullLiteral: function(locInfo) {
+    this.loc = locInfo;
+    this.type = 'NullLiteral';
+    this.original = this.value = null;
+  },
+
   Hash: function(pairs, locInfo) {
     this.loc = locInfo;
     this.type = 'Hash';
diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js
index e1b4dfb31..a39082db1 100644
--- a/lib/handlebars/compiler/compiler.js
+++ b/lib/handlebars/compiler/compiler.js
@@ -273,6 +273,14 @@ Compiler.prototype = {
     this.opcode('pushLiteral', bool.value);
   },
 
+  UndefinedLiteral: function() {
+    this.opcode('pushLiteral', 'undefined');
+  },
+
+  NullLiteral: function() {
+    this.opcode('pushLiteral', 'null');
+  },
+
   Hash: function(hash) {
     var pairs = hash.pairs, i, l;
 
diff --git a/lib/handlebars/compiler/printer.js b/lib/handlebars/compiler/printer.js
index 55232cc45..dcc73c35c 100644
--- a/lib/handlebars/compiler/printer.js
+++ b/lib/handlebars/compiler/printer.js
@@ -124,6 +124,14 @@ PrintVisitor.prototype.BooleanLiteral = function(bool) {
   return "BOOLEAN{" + bool.value + "}";
 };
 
+PrintVisitor.prototype.UndefinedLiteral = function() {
+  return 'UNDEFINED';
+};
+
+PrintVisitor.prototype.NullLiteral = function() {
+  return 'NULL';
+};
+
 PrintVisitor.prototype.Hash = function(hash) {
   var pairs = hash.pairs;
   var joinedPairs = [];
diff --git a/lib/handlebars/compiler/visitor.js b/lib/handlebars/compiler/visitor.js
index 4101a4f04..6e4168e1e 100644
--- a/lib/handlebars/compiler/visitor.js
+++ b/lib/handlebars/compiler/visitor.js
@@ -110,6 +110,8 @@ Visitor.prototype = {
   StringLiteral: function(/* string */) {},
   NumberLiteral: function(/* number */) {},
   BooleanLiteral: function(/* bool */) {},
+  UndefinedLiteral: function(/* literal */) {},
+  NullLiteral: function(/* literal */) {},
 
   Hash: function(hash) {
     this.acceptArray(hash.pairs);
diff --git a/spec/basic.js b/spec/basic.js
index 9b6678a5a..11002e4eb 100644
--- a/spec/basic.js
+++ b/spec/basic.js
@@ -66,6 +66,16 @@ describe("basic context", function() {
     shouldCompileTo('val: {{{val1/val2}}}', {val1: {val2: false}}, 'val: false');
   });
 
+  it('should handle undefined and null', function() {
+    shouldCompileTo('{{awesome undefined null}}',
+        {
+          awesome: function(_undefined, _null, options) {
+            return (_undefined === undefined) + ' ' + (_null === null) + ' ' + (typeof options);
+          }
+        },
+        'true true object');
+  });
+
   it("newlines", function() {
       shouldCompileTo("Alan's\nTest", {}, "Alan's\nTest");
       shouldCompileTo("Alan's\rTest", {}, "Alan's\rTest");
diff --git a/spec/javascript-compiler.js b/spec/javascript-compiler.js
index fb7865854..f47ddebe7 100644
--- a/spec/javascript-compiler.js
+++ b/spec/javascript-compiler.js
@@ -23,7 +23,7 @@ describe('javascript-compiler api', function() {
     // Tests nameLookup dot vs. bracket behavior.  Bracket is required in certain cases
     // to avoid errors in older browsers.
     it('should handle reserved words', function() {
-      shouldCompileTo("{{foo}} {{~null~}}", { foo: "food" }, "food");
+      shouldCompileTo("{{foo}} {{~[null]~}}", { foo: "food" }, "food");
     });
   });
   describe('#compilerInfo', function() {
diff --git a/spec/parser.js b/spec/parser.js
index 3d3dccff3..6f5a660c0 100644
--- a/spec/parser.js
+++ b/spec/parser.js
@@ -58,6 +58,10 @@ describe('parser', function() {
     equals(ast_for("{{foo false}}"), "{{ PATH:foo [BOOLEAN{false}] }}\n");
   });
 
+  it('parses mustaches with undefined and null parameters', function() {
+    equals(ast_for("{{foo undefined null}}"), "{{ PATH:foo [UNDEFINED, NULL] }}\n");
+  });
+
   it('parses mutaches with DATA parameters', function() {
     equals(ast_for("{{foo @bar}}"), "{{ PATH:foo [@PATH:bar] }}\n");
   });
diff --git a/spec/tokenizer.js b/spec/tokenizer.js
index 0a5143bef..26a1c3b51 100644
--- a/spec/tokenizer.js
+++ b/spec/tokenizer.js
@@ -322,6 +322,13 @@ describe('Tokenizer', function() {
     shouldBeToken(result[2], "BOOLEAN", "false");
   });
 
+  it('tokenizes undefined and null', function() {
+    var result = tokenize('{{ foo undefined null }}');
+    shouldMatchTokens(result, ['OPEN', 'ID', 'UNDEFINED', 'NULL', 'CLOSE']);
+    shouldBeToken(result[2], 'UNDEFINED', 'undefined');
+    shouldBeToken(result[3], 'NULL', 'null');
+  });
+
   it('tokenizes hash arguments', function() {
     var result = tokenize("{{ foo bar=baz }}");
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
diff --git a/spec/visitor.js b/spec/visitor.js
index 32172309c..8b9ef9f60 100644
--- a/spec/visitor.js
+++ b/spec/visitor.js
@@ -9,7 +9,7 @@ describe('Visitor', function() {
     // Simply run the thing and make sure it does not fail and that all of the
     // stub methods are executed
     var visitor = new Handlebars.Visitor();
-    visitor.accept(Handlebars.parse('{{foo}}{{#foo (bar 1 "1" true) foo=@data}}{{!comment}}{{> bar }} {{/foo}}'));
+    visitor.accept(Handlebars.parse('{{foo}}{{#foo (bar 1 "1" true undefined null) foo=@data}}{{!comment}}{{> bar }} {{/foo}}'));
   });
 
   it('should traverse to stubs', function() {
diff --git a/src/handlebars.l b/src/handlebars.l
index ace0263fc..55d8efc2d 100644
--- a/src/handlebars.l
+++ b/src/handlebars.l
@@ -102,6 +102,8 @@ ID    [^\s!"#%-,\.\/;->@\[-\^`\{-~]+/{LOOKAHEAD}
 <mu>"@"                          return 'DATA';
 <mu>"true"/{LITERAL_LOOKAHEAD}   return 'BOOLEAN';
 <mu>"false"/{LITERAL_LOOKAHEAD}  return 'BOOLEAN';
+<mu>"undefined"/{LITERAL_LOOKAHEAD} return 'UNDEFINED';
+<mu>"null"/{LITERAL_LOOKAHEAD}   return 'NULL';
 <mu>\-?[0-9]+(?:\.[0-9]+)?/{LITERAL_LOOKAHEAD} return 'NUMBER';
 <mu>"as"\s+"|"                   return 'OPEN_BLOCK_PARAMS';
 <mu>"|"                          return 'CLOSE_BLOCK_PARAMS';
diff --git a/src/handlebars.yy b/src/handlebars.yy
index 18f03b902..d7245785a 100644
--- a/src/handlebars.yy
+++ b/src/handlebars.yy
@@ -83,6 +83,8 @@ partial
 param
   : helperName -> $1
   | sexpr -> $1
+  | UNDEFINED -> new yy.UndefinedLiteral(yy.locInfo(@$))
+  | NULL -> new yy.NullLiteral(yy.locInfo(@$))
   ;
 
 sexpr

From c699d0b82f5f006bbd11d2dfcc3b7e563ff46959 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Tue, 7 Apr 2015 23:37:46 -0500
Subject: [PATCH 04/17] Remove vestigial code

---
 lib/handlebars/compiler/visitor.js | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/lib/handlebars/compiler/visitor.js b/lib/handlebars/compiler/visitor.js
index 6e4168e1e..b45b268e3 100644
--- a/lib/handlebars/compiler/visitor.js
+++ b/lib/handlebars/compiler/visitor.js
@@ -99,11 +99,6 @@ Visitor.prototype = {
     this.acceptArray(sexpr.params);
     this.acceptKey(sexpr, 'hash');
   },
-  PartialExpression: function(partial) {
-    this.acceptRequired(partial, 'name');
-    this.acceptArray(partial.params);
-    this.acceptKey(partial, 'hash');
-  },
 
   PathExpression: function(/* path */) {},
 

From 37a664bf6438bde0ee827a68da4cbd95a21cf52e Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Tue, 7 Apr 2015 23:38:05 -0500
Subject: [PATCH 05/17] Ignore branches tested without coverage monitoring

---
 lib/handlebars/compiler/code-gen.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/handlebars/compiler/code-gen.js b/lib/handlebars/compiler/code-gen.js
index e99809587..92020f00e 100644
--- a/lib/handlebars/compiler/code-gen.js
+++ b/lib/handlebars/compiler/code-gen.js
@@ -3,6 +3,7 @@ import {isArray} from "../utils";
 var SourceNode;
 
 try {
+  /* istanbul ignore next */
   if (typeof define !== 'function' || !define.amd) {
     // We don't support this in AMD environments. For these environments, we asusme that
     // they are running on the browser and thus have no need for the source-map library.
@@ -13,8 +14,8 @@ try {
   /* NOP */
 }
 
+/* istanbul ignore if: tested but not covered in istanbul due to dist build  */
 if (!SourceNode) {
-  /* istanbul ignore next: tested but not covered in istanbul due to dist build  */
   SourceNode = function(line, column, srcFile, chunks) {
     this.src = '';
     if (chunks) {

From dfd141cd3566c52c271c7470ff690fa6ace6f548 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Mon, 13 Apr 2015 21:18:53 -0500
Subject: [PATCH 06/17] Allow undefined and null in helper names

---
 spec/basic.js               | 14 ++++++++++++++
 spec/javascript-compiler.js |  2 +-
 spec/parser.js              |  4 ++++
 src/handlebars.yy           |  4 ++--
 4 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/spec/basic.js b/spec/basic.js
index 11002e4eb..e634d4137 100644
--- a/spec/basic.js
+++ b/spec/basic.js
@@ -74,6 +74,20 @@ describe("basic context", function() {
           }
         },
         'true true object');
+    shouldCompileTo('{{undefined}}',
+        {
+          undefined: function() {
+            return 'undefined!';
+          }
+        },
+        'undefined!');
+    shouldCompileTo('{{null}}',
+        {
+          null: function() {
+            return 'null!';
+          }
+        },
+        'null!');
   });
 
   it("newlines", function() {
diff --git a/spec/javascript-compiler.js b/spec/javascript-compiler.js
index f47ddebe7..fb7865854 100644
--- a/spec/javascript-compiler.js
+++ b/spec/javascript-compiler.js
@@ -23,7 +23,7 @@ describe('javascript-compiler api', function() {
     // Tests nameLookup dot vs. bracket behavior.  Bracket is required in certain cases
     // to avoid errors in older browsers.
     it('should handle reserved words', function() {
-      shouldCompileTo("{{foo}} {{~[null]~}}", { foo: "food" }, "food");
+      shouldCompileTo("{{foo}} {{~null~}}", { foo: "food" }, "food");
     });
   });
   describe('#compilerInfo', function() {
diff --git a/spec/parser.js b/spec/parser.js
index 6f5a660c0..d799e08a2 100644
--- a/spec/parser.js
+++ b/spec/parser.js
@@ -58,6 +58,10 @@ describe('parser', function() {
     equals(ast_for("{{foo false}}"), "{{ PATH:foo [BOOLEAN{false}] }}\n");
   });
 
+  it('parses mustaches with undefined and null paths', function() {
+    equals(ast_for("{{undefined}}"), "{{ UNDEFINED [] }}\n");
+    equals(ast_for("{{null}}"), "{{ NULL [] }}\n");
+  });
   it('parses mustaches with undefined and null parameters', function() {
     equals(ast_for("{{foo undefined null}}"), "{{ PATH:foo [UNDEFINED, NULL] }}\n");
   });
diff --git a/src/handlebars.yy b/src/handlebars.yy
index d7245785a..01ef7fbc4 100644
--- a/src/handlebars.yy
+++ b/src/handlebars.yy
@@ -83,8 +83,6 @@ partial
 param
   : helperName -> $1
   | sexpr -> $1
-  | UNDEFINED -> new yy.UndefinedLiteral(yy.locInfo(@$))
-  | NULL -> new yy.NullLiteral(yy.locInfo(@$))
   ;
 
 sexpr
@@ -109,6 +107,8 @@ helperName
   | STRING -> new yy.StringLiteral($1, yy.locInfo(@$))
   | NUMBER -> new yy.NumberLiteral($1, yy.locInfo(@$))
   | BOOLEAN -> new yy.BooleanLiteral($1, yy.locInfo(@$))
+  | UNDEFINED -> new yy.UndefinedLiteral(yy.locInfo(@$))
+  | NULL -> new yy.NullLiteral(yy.locInfo(@$))
   ;
 
 partialName

From a7160a8d2745de95cb9da7d20ff02795b0d3f784 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Mon, 13 Apr 2015 21:25:53 -0500
Subject: [PATCH 07/17] Expose Visitor in full browser build

Fixes #994
---
 lib/handlebars.js | 3 +++
 lib/index.js      | 2 --
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/handlebars.js b/lib/handlebars.js
index 81b7cfbd2..6398a0511 100644
--- a/lib/handlebars.js
+++ b/lib/handlebars.js
@@ -6,6 +6,7 @@ import AST from "./handlebars/compiler/ast";
 import { parser as Parser, parse } from "./handlebars/compiler/base";
 import { Compiler, compile, precompile } from "./handlebars/compiler/compiler";
 import JavaScriptCompiler from "./handlebars/compiler/javascript-compiler";
+import Visitor from "./handlebars/compiler/visitor";
 
 var _create = Handlebars.create;
 var create = function() {
@@ -30,6 +31,8 @@ var create = function() {
 Handlebars = create();
 Handlebars.create = create;
 
+Handlebars.Visitor = Visitor;
+
 /*jshint -W040 */
 /* istanbul ignore next */
 var root = typeof global !== 'undefined' ? global : window,
diff --git a/lib/index.js b/lib/index.js
index 790aab73a..8213d14e5 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -5,8 +5,6 @@
 
 var handlebars = require('../dist/cjs/handlebars')["default"];
 
-handlebars.Visitor = require('../dist/cjs/handlebars/compiler/visitor')["default"];
-
 var printer = require('../dist/cjs/handlebars/compiler/printer');
 handlebars.PrintVisitor = printer.PrintVisitor;
 handlebars.print = printer.print;

From 54e743a09a0e7524edd9e76c029eff53a90f9cba Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Tue, 14 Apr 2015 01:12:39 -0500
Subject: [PATCH 08/17] Allow this references in literal statements

Fixes #967
---
 lib/handlebars/compiler/helpers.js | 15 +++++++++++++--
 spec/basic.js                      | 19 +++++++++++++++----
 src/handlebars.l                   |  2 +-
 src/handlebars.yy                  |  8 ++++----
 4 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/lib/handlebars/compiler/helpers.js b/lib/handlebars/compiler/helpers.js
index beaf98869..4a502d800 100644
--- a/lib/handlebars/compiler/helpers.js
+++ b/lib/handlebars/compiler/helpers.js
@@ -12,6 +12,14 @@ export function SourceLocation(source, locInfo) {
   };
 }
 
+export function id(token) {
+  if (/^\[.*\]$/.test(token)) {
+    return token.substr(1, token.length - 2);
+  } else {
+    return token;
+  }
+}
+
 export function stripFlags(open, close) {
   return {
     open: open.charAt(2) === '~',
@@ -34,10 +42,13 @@ export function preparePath(data, parts, locInfo) {
       depthString = '';
 
   for(var i=0,l=parts.length; i<l; i++) {
-    var part = parts[i].part;
+    var part = parts[i].part,
+        // If we have [] syntax then we do not treat path references as operators,
+        // i.e. foo.[this] resolves to approximately context.foo['this']
+        isLiteral = parts[i].original !== part;
     original += (parts[i].separator || '') + part;
 
-    if (part === '..' || part === '.' || part === 'this') {
+    if (!isLiteral && (part === '..' || part === '.' || part === 'this')) {
       if (dig.length > 0) {
         throw new Exception('Invalid path: ' + original, {loc: locInfo});
       } else if (part === '..') {
diff --git a/spec/basic.js b/spec/basic.js
index e634d4137..37aa8cfb5 100644
--- a/spec/basic.js
+++ b/spec/basic.js
@@ -227,10 +227,12 @@ describe("basic context", function() {
   });
 
   it("this keyword nested inside path", function() {
-    var string = "{{#hellos}}{{text/this/foo}}{{/hellos}}";
     shouldThrow(function() {
-      CompilerContext.compile(string);
-    }, Error);
+      CompilerContext.compile('{{#hellos}}{{text/this/foo}}{{/hellos}}');
+    }, Error, 'Invalid path: text/this - 1:13');
+
+    shouldCompileTo('{{[this]}}', {'this': 'bar'}, 'bar');
+    shouldCompileTo('{{text/[this]}}', {text: {'this': 'bar'}}, 'bar');
   });
 
   it("this keyword in helpers", function() {
@@ -251,7 +253,16 @@ describe("basic context", function() {
     var string = "{{#hellos}}{{foo text/this/foo}}{{/hellos}}";
     shouldThrow(function() {
       CompilerContext.compile(string);
-    }, Error);
+    }, Error, 'Invalid path: text/this - 1:17');
+
+    shouldCompileTo(
+        '{{foo [this]}}',
+        {foo: function(value) { return value; }, 'this': 'bar'},
+        'bar');
+    shouldCompileTo(
+        '{{foo text/[this]}}',
+        {foo: function(value) { return value; }, text: {'this': 'bar'}},
+        'bar');
   });
 
   it('pass string literals', function() {
diff --git a/src/handlebars.l b/src/handlebars.l
index 55d8efc2d..ff2128355 100644
--- a/src/handlebars.l
+++ b/src/handlebars.l
@@ -110,7 +110,7 @@ ID    [^\s!"#%-,\.\/;->@\[-\^`\{-~]+/{LOOKAHEAD}
 
 <mu>{ID}                         return 'ID';
 
-<mu>'['[^\]]*']'                 yytext = strip(1,2); return 'ID';
+<mu>'['[^\]]*']'                 return 'ID';
 <mu>.                            return 'INVALID';
 
 <INITIAL,mu><<EOF>>              return 'EOF';
diff --git a/src/handlebars.yy b/src/handlebars.yy
index 01ef7fbc4..d67a7da7e 100644
--- a/src/handlebars.yy
+++ b/src/handlebars.yy
@@ -94,11 +94,11 @@ hash
   ;
 
 hashSegment
-  : ID EQUALS param -> new yy.HashPair($1, $3, yy.locInfo(@$))
+  : ID EQUALS param -> new yy.HashPair(yy.id($1), $3, yy.locInfo(@$))
   ;
 
 blockParams
-  : OPEN_BLOCK_PARAMS ID+ CLOSE_BLOCK_PARAMS -> $2
+  : OPEN_BLOCK_PARAMS ID+ CLOSE_BLOCK_PARAMS -> yy.id($2)
   ;
 
 helperName
@@ -125,6 +125,6 @@ path
   ;
 
 pathSegments
-  : pathSegments SEP ID { $1.push({part: $3, separator: $2}); $$ = $1; }
-  | ID -> [{part: $1}]
+  : pathSegments SEP ID { $1.push({part: yy.id($3), original: $3, separator: $2}); $$ = $1; }
+  | ID -> [{part: yy.id($1), original: $1}]
   ;

From a009a97a2e88c86984137ece113b454246114377 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Tue, 14 Apr 2015 01:14:18 -0500
Subject: [PATCH 09/17] Use captureStackTrace for error handler

Provides more stable error stack reporting when running under v8 environments.
---
 lib/handlebars/exception.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/handlebars/exception.js b/lib/handlebars/exception.js
index 3fde1c14f..053aea871 100644
--- a/lib/handlebars/exception.js
+++ b/lib/handlebars/exception.js
@@ -19,6 +19,10 @@ function Exception(message, node) {
     this[errorProps[idx]] = tmp[errorProps[idx]];
   }
 
+  if (Error.captureStackTrace) {
+    Error.captureStackTrace(this, Exception);
+  }
+
   if (loc) {
     this.lineNumber = line;
     this.column = column;

From 2a02261a5bc78f246c63dd8d467a12f2c1f63734 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Tue, 14 Apr 2015 22:57:15 -0500
Subject: [PATCH 10/17] Fix IE test freakout

---
 spec/basic.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/spec/basic.js b/spec/basic.js
index 37aa8cfb5..323a103fc 100644
--- a/spec/basic.js
+++ b/spec/basic.js
@@ -76,14 +76,14 @@ describe("basic context", function() {
         'true true object');
     shouldCompileTo('{{undefined}}',
         {
-          undefined: function() {
+          'undefined': function() {
             return 'undefined!';
           }
         },
         'undefined!');
     shouldCompileTo('{{null}}',
         {
-          null: function() {
+          'null': function() {
             return 'null!';
           }
         },

From e3d3eda2e1e03e997d417affc09974446b4ca701 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Thu, 16 Apr 2015 15:42:46 -0500
Subject: [PATCH 11/17] Add full support for es6

Converts the tool chain to use babel, eslint, and webpack vs. the previous proprietary solutions.

Additionally begins enforcing additional linting concerns as well as updates the code to reflect these rules.

Fixes #855
Fixes #993
---
 .eslintrc                                     | 186 ++++++
 Gruntfile.js                                  |  99 ++--
 lib/handlebars.js                             |  38 +-
 lib/handlebars.runtime.js                     |  16 +-
 lib/handlebars/base.js                        |  62 +-
 lib/handlebars/compiler/ast.js                |   9 +-
 lib/handlebars/compiler/base.js               |  10 +-
 lib/handlebars/compiler/code-gen.js           |   9 +-
 lib/handlebars/compiler/compiler.js           |  54 +-
 lib/handlebars/compiler/helpers.js            |   6 +-
 .../compiler/javascript-compiler.js           |  88 +--
 lib/handlebars/compiler/printer.js            |  34 +-
 lib/handlebars/compiler/visitor.js            |   4 +-
 lib/handlebars/compiler/whitespace-control.js |  23 +-
 lib/handlebars/runtime.js                     |  60 +-
 lib/handlebars/safe-string.js                 |   2 +-
 lib/handlebars/utils.js                       |  14 +-
 lib/index.js                                  |  16 +-
 lib/precompiler.js                            |  18 +-
 package.json                                  |   6 +-
 spec/.eslintrc                                |  34 ++
 spec/ast.js                                   |  79 ++-
 spec/basic.js                                 | 237 ++++----
 spec/blocks.js                                | 147 +++--
 spec/builtins.js                              | 289 +++++-----
 spec/compiler.js                              |  10 +-
 spec/data.js                                  | 163 +++---
 spec/env/browser.js                           |   6 +-
 spec/env/common.js                            |   5 +-
 spec/env/node.js                              |   3 +-
 spec/env/runner.js                            |   5 +-
 spec/env/runtime.js                           |  16 +-
 spec/helpers.js                               | 531 +++++++++---------
 spec/javascript-compiler.js                   |  13 +-
 spec/parser.js                                | 149 +++--
 spec/partials.js                              | 213 ++++---
 spec/precompiler.js                           |   4 +-
 spec/regressions.js                           |  76 +--
 spec/require.js                               |  14 +-
 spec/runtime.js                               |   2 -
 spec/source-map.js                            |  11 +-
 spec/spec.js                                  |  11 +-
 spec/strict.js                                |   1 -
 spec/string-params.js                         |  89 ++-
 spec/subexpressions.js                        | 160 +++---
 spec/tokenizer.js                             | 261 +++++----
 spec/track-ids.js                             |  28 +-
 spec/utils.js                                 |  14 +-
 spec/visitor.js                               |   2 -
 spec/whitespace-control.js                    |   2 -
 tasks/version.js                              |   2 +-
 51 files changed, 1789 insertions(+), 1542 deletions(-)
 create mode 100644 .eslintrc
 create mode 100644 spec/.eslintrc

diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 000000000..b6420d1f2
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,186 @@
+{
+  "globals": {
+    "self": false
+  },
+  "env": {
+    "node": true
+  },
+  "ecmaFeatures": {
+    "modules": true
+  },
+  "rules": {
+    // Possible Errors //
+    //-----------------//
+
+    "comma-dangle": [2, "never"],
+    "no-cond-assign": [2, "except-parens"],
+
+    // Allow for debugging
+    "no-console": 1,
+
+    "no-constant-condition": 2,
+    "no-control-regex": 2,
+
+    // Allow for debugging
+    "no-debugger": 1,
+
+    "no-dupe-args": 2,
+    "no-dupe-keys": 2,
+    "no-duplicate-case": 2,
+    "no-empty": 2,
+    "no-empty-class": 2,
+    "no-ex-assign": 2,
+    "no-extra-boolean-cast": 2,
+    "no-extra-parens": 0,
+    "no-extra-semi": 2,
+    "no-func-assign": 2,
+
+    // Stylistic... might consider disallowing in the future
+    "no-inner-declarations": 0,
+
+    "no-invalid-regexp": 2,
+    "no-irregular-whitespace": 2,
+    "no-negated-in-lhs": 2,
+    "no-obj-calls": 2,
+    "no-regex-spaces": 2,
+    "no-reserved-keys": 2,    // Important for IE
+    "no-sparse-arrays": 0,
+
+    // Optimizer and coverage will handle/highlight this and can be useful for debugging
+    "no-unreachable": 1,
+
+    "use-isnan": 2,
+    "valid-jsdoc": 0,
+    "valid-typeof": 2,
+
+
+    // Best Practices //
+    //----------------//
+    "block-scoped-var": 0,
+    "complexity": 0,
+    "consistent-return": 0,
+    "curly": 2,
+    "default-case": 1,
+    "dot-notation": [2, {"allowKeywords": false}],
+    "eqeqeq": 0,
+    "guard-for-in": 1,
+    "no-alert": 2,
+    "no-caller": 2,
+    "no-div-regex": 1,
+    "no-else-return": 0,
+    "no-empty-label": 2,
+    "no-eq-null": 0,
+    "no-eval": 2,
+    "no-extend-native": 2,
+    "no-extra-bind": 2,
+    "no-fallthrough": 2,
+    "no-floating-decimal": 2,
+    "no-implied-eval": 2,
+    "no-iterator": 2,
+    "no-labels": 2,
+    "no-lone-blocks": 2,
+    "no-loop-func": 2,
+    "no-multi-spaces": 2,
+    "no-multi-str": 1,
+    "no-native-reassign": 2,
+    "no-new": 2,
+    "no-new-func": 2,
+    "no-new-wrappers": 2,
+    "no-octal": 2,
+    "no-octal-escape": 2,
+    "no-param-reassign": 0,
+    "no-process-env": 2,
+    "no-proto": 2,
+    "no-redeclare": 2,
+    "no-return-assign": 2,
+    "no-script-url": 2,
+    "no-self-compare": 2,
+    "no-sequences": 2,
+    "no-throw-literal": 2,
+    "no-unused-expressions": 2,
+    "no-void": 0,
+    "no-warning-comments": 1,
+    "no-with": 2,
+    "radix": 2,
+    "vars-on-top": 0,
+    "wrap-iife": 2,
+    "yoda": 0,
+
+
+    // Strict //
+    //--------//
+    "strict": 0,
+
+
+    // Variables //
+    //-----------//
+    "no-catch-shadow": 2,
+    "no-delete-var": 2,
+    "no-label-var": 2,
+    "no-shadow": 2,
+    "no-shadow-restricted-names": 2,
+    "no-undef": 2,
+    "no-undef-init": 2,
+    "no-undefined": 0,
+    "no-unused-vars": [2, {"vars": "all", "args": "after-used"}],    
+    "no-use-before-define": [2, "nofunc"],
+
+
+    // Node.js //
+    //---------//
+    // Others left to environment defaults
+    "no-mixed-requires": 0,
+
+
+    // Stylistic //
+    //-----------//
+    "indent": 0,
+    "brace-style": [2, "1tbs", {"allowSingleLine": true}],
+    "camelcase": 2,
+    "comma-spacing": [2, {"before": false, "after": true}],
+    "comma-style": [2, "last"],
+    "consistent-this": [1, "self"],
+    "eol-last": 2,
+    "func-names": 0,
+    "func-style": [2, "declaration"],
+    "key-spacing": [2, {
+        "beforeColon": false,
+        "afterColon": true
+    }],
+    "max-nested-callbacks": 0,
+    "new-cap": 2,
+    "new-parens": 2,
+    "newline-after-var": 0,
+    "no-array-constructor": 2,
+    "no-continue": 0,
+    "no-inline-comments": 0,
+    "no-lonely-if": 2,
+    "no-mixed-spaces-and-tabs": 2,
+    "no-multiple-empty-lines": 0,
+    "no-nested-ternary": 1,
+    "no-new-object": 2,
+    "no-spaced-func": 2,
+    "no-ternary": 0,
+    "no-trailing-spaces": 2,
+    "no-underscore-dangle": 0,
+    "no-wrap-func": 2,
+    "one-var": 0,
+    "operator-assignment": 0,
+    "padded-blocks": 0,
+    "quote-props": 0,
+    "quotes": [2, "single", "avoid-escape"],
+    "semi": 2,
+    "semi-spacing": [2, {"before": false, "after": true}],
+    "sort-vars": 0,
+    "space-after-keywords": [2, "always"],
+    "space-before-blocks": [2, "always"],
+    "space-before-function-paren": [2, {"anonymous": "never", "named": "never"}],
+    "space-in-brackets": 0,
+    "space-in-parens": [2, "never"],
+    "space-infix-ops": 2,
+    "space-return-throw-case": 2,
+    "space-unary-ops": 2,
+    "spaced-line-comment": 2,
+    "wrap-regex": 1
+  }
+}
\ No newline at end of file
diff --git a/Gruntfile.js b/Gruntfile.js
index b73974059..48630046c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,16 +1,16 @@
-var childProcess = require('child_process');
-
+/*eslint-disable no-process-env */
 module.exports = function(grunt) {
 
   grunt.initConfig({
     pkg: grunt.file.readJSON('package.json'),
 
-    jshint: {
+    eslint: {
       options: {
-        jshintrc: '.jshintrc'
       },
       files: [
-        'dist/cjs/**/!(*.min|parser).js'
+        '*.js',
+        'lib/**/!(*.min|parser).js',
+        'spec/**/!(*.amd|json2|require).js'
       ]
     },
 
@@ -19,7 +19,7 @@ module.exports = function(grunt) {
     copy: {
       dist: {
         options: {
-          processContent: function(content, path) {
+          processContent: function(content) {
             return grunt.template.process('/*!\n\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n@license\n*/\n')
                 + content;
           }
@@ -41,54 +41,78 @@ module.exports = function(grunt) {
       }
     },
 
-    packager: {
-      global: {
-        type: 'umd',
-        export: 'Handlebars',
-        files: [{
-          cwd: 'lib/',
-          expand: true,
-          src: ['handlebars*.js'],
-          dest: 'dist/'
-        }]
+    babel: {
+      options: {
+        loose: ['es6.modules']
       },
-
       amd: {
-        type: 'amd',
-        anonymous: true,
+        options: {
+          modules: 'amd'
+        },
         files: [{
           expand: true,
           cwd: 'lib/',
-          src: '**/!(index).js',
+          src: '**/!(index|precompiler).js',
           dest: 'dist/amd/'
         }]
       },
 
       cjs: {
-        type: 'cjs',
+        options: {
+          modules: 'common'
+        },
         files: [{
-          expand: true,
           cwd: 'lib/',
+          expand: true,
           src: '**/!(index).js',
           dest: 'dist/cjs/'
         }]
       }
     },
+    webpack: {
+      options: {
+        context: __dirname,
+        module: {
+          loaders: [
+            // the optional 'runtime' transformer tells babel to require the runtime instead of inlining it.
+            { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?optional=runtime&loose=es6.modules' }
+          ]
+        },
+        output: {
+          path: 'dist/',
+          library: 'Handlebars',
+          libraryType: 'umd'
+        }
+      },
+      handlebars: {
+        entry: './lib/handlebars.js',
+        output: {
+          filename: 'handlebars.js'
+        }
+      },
+      runtime: {
+        entry: './lib/handlebars.runtime.js',
+        output: {
+          filename: 'handlebars.runtime.js'
+        }
+      }
+    },
+
     requirejs: {
       options: {
-        optimize: "none",
-        baseUrl: "dist/amd/"
+        optimize: 'none',
+        baseUrl: 'dist/amd/'
       },
       dist: {
         options: {
-          name: "handlebars",
-          out: "dist/handlebars.amd.js"
+          name: 'handlebars',
+          out: 'dist/handlebars.amd.js'
         }
       },
       runtime: {
         options: {
-          name: "handlebars.runtime",
-          out: "dist/handlebars.runtime.amd.js"
+          name: 'handlebars.runtime',
+          out: 'dist/handlebars.runtime.amd.js'
         }
       }
     },
@@ -172,18 +196,18 @@ module.exports = function(grunt) {
   });
 
   // Build a new version of the library
-  this.registerTask('build', "Builds a distributable version of the current project", [
+  this.registerTask('build', 'Builds a distributable version of the current project', [
+                    'eslint',
                     'parser',
                     'node',
-                    'globals',
-                    'jshint']);
+                    'globals']);
 
-  this.registerTask('amd', ['packager:amd', 'requirejs']);
-  this.registerTask('node', ['packager:cjs']);
-  this.registerTask('globals', ['packager:global']);
+  this.registerTask('amd', ['babel:amd', 'requirejs']);
+  this.registerTask('node', ['babel:cjs']);
+  this.registerTask('globals', ['webpack']);
   this.registerTask('tests', ['concat:tests']);
 
-  this.registerTask('release', 'Build final packages', ['amd', 'jshint', 'uglify', 'copy:dist', 'copy:components', 'copy:cdnjs']);
+  this.registerTask('release', 'Build final packages', ['eslint', 'amd', 'uglify', 'copy:dist', 'copy:components', 'copy:cdnjs']);
 
   // Load tasks from npm
   grunt.loadNpmTasks('grunt-contrib-clean');
@@ -191,11 +215,12 @@ module.exports = function(grunt) {
   grunt.loadNpmTasks('grunt-contrib-connect');
   grunt.loadNpmTasks('grunt-contrib-copy');
   grunt.loadNpmTasks('grunt-contrib-requirejs');
-  grunt.loadNpmTasks('grunt-contrib-jshint');
   grunt.loadNpmTasks('grunt-contrib-uglify');
   grunt.loadNpmTasks('grunt-contrib-watch');
+  grunt.loadNpmTasks('grunt-babel');
+  grunt.loadNpmTasks('grunt-eslint');
   grunt.loadNpmTasks('grunt-saucelabs');
-  grunt.loadNpmTasks('es6-module-packager');
+  grunt.loadNpmTasks('grunt-webpack');
 
   grunt.task.loadTasks('tasks');
 
diff --git a/lib/handlebars.js b/lib/handlebars.js
index 6398a0511..38144a363 100644
--- a/lib/handlebars.js
+++ b/lib/handlebars.js
@@ -1,21 +1,20 @@
-/*globals Handlebars: true */
-import Handlebars from "./handlebars.runtime";
+import Handlebars from './handlebars.runtime';
 
 // Compiler imports
-import AST from "./handlebars/compiler/ast";
-import { parser as Parser, parse } from "./handlebars/compiler/base";
-import { Compiler, compile, precompile } from "./handlebars/compiler/compiler";
-import JavaScriptCompiler from "./handlebars/compiler/javascript-compiler";
-import Visitor from "./handlebars/compiler/visitor";
+import AST from './handlebars/compiler/ast';
+import { parser as Parser, parse } from './handlebars/compiler/base';
+import { Compiler, compile, precompile } from './handlebars/compiler/compiler';
+import JavaScriptCompiler from './handlebars/compiler/javascript-compiler';
+import Visitor from './handlebars/compiler/visitor';
 
 var _create = Handlebars.create;
-var create = function() {
+function create() {
   var hb = _create();
 
   hb.compile = function(input, options) {
     return compile(input, options, hb);
   };
-  hb.precompile = function (input, options) {
+  hb.precompile = function(input, options) {
     return precompile(input, options, hb);
   };
 
@@ -26,24 +25,23 @@ var create = function() {
   hb.parse = parse;
 
   return hb;
-};
+}
 
-Handlebars = create();
-Handlebars.create = create;
+var inst = create();
+inst.create = create;
 
-Handlebars.Visitor = Visitor;
+inst.Visitor = Visitor;
 
 /*jshint -W040 */
 /* istanbul ignore next */
-var root = typeof global !== 'undefined' ? global : window,
-    $Handlebars = root.Handlebars;
+var $Handlebars = global.Handlebars;
 /* istanbul ignore next */
-Handlebars.noConflict = function() {
-  if (root.Handlebars === Handlebars) {
-    root.Handlebars = $Handlebars;
+inst.noConflict = function() {
+  if (global.Handlebars === inst) {
+    global.Handlebars = $Handlebars;
   }
 };
 
-Handlebars['default'] = Handlebars;
+inst['default'] = inst;
 
-export default Handlebars;
+export default inst;
diff --git a/lib/handlebars.runtime.js b/lib/handlebars.runtime.js
index ef00e2856..c502b5ca7 100644
--- a/lib/handlebars.runtime.js
+++ b/lib/handlebars.runtime.js
@@ -1,15 +1,15 @@
-/*globals Handlebars: true */
-module base from "./handlebars/base";
+/*global window */
+import * as base from './handlebars/base';
 
 // Each of these augment the Handlebars object. No need to setup here.
 // (This is done to easily share code between commonjs and browse envs)
-import SafeString from "./handlebars/safe-string";
-import Exception from "./handlebars/exception";
-module Utils from "./handlebars/utils";
-module runtime from "./handlebars/runtime";
+import SafeString from './handlebars/safe-string';
+import Exception from './handlebars/exception';
+import * as Utils from './handlebars/utils';
+import * as runtime from './handlebars/runtime';
 
 // For compatibility and usage outside of module systems, make the Handlebars object a namespace
-var create = function() {
+function create() {
   var hb = new base.HandlebarsEnvironment();
 
   Utils.extend(hb, base);
@@ -24,7 +24,7 @@ var create = function() {
   };
 
   return hb;
-};
+}
 
 var Handlebars = create();
 Handlebars.create = create;
diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js
index 293d5eaef..771cb9ccf 100644
--- a/lib/handlebars/base.js
+++ b/lib/handlebars/base.js
@@ -1,7 +1,7 @@
-module Utils from "./utils";
-import Exception from "./exception";
+import * as Utils from './utils';
+import Exception from './exception';
 
-export var VERSION = "3.0.1";
+export var VERSION = '3.0.1';
 export var COMPILER_REVISION = 6;
 
 export var REVISION_CHANGES = {
@@ -45,7 +45,7 @@ HandlebarsEnvironment.prototype = {
 
   registerPartial: function(name, partial) {
     if (toString.call(name) === objectType) {
-      Utils.extend(this.partials,  name);
+      Utils.extend(this.partials, name);
     } else {
       if (typeof partial === 'undefined') {
         throw new Exception('Attempting to register a partial as undefined');
@@ -60,12 +60,12 @@ HandlebarsEnvironment.prototype = {
 
 function registerDefaultHelpers(instance) {
   instance.registerHelper('helperMissing', function(/* [args, ]options */) {
-    if(arguments.length === 1) {
+    if (arguments.length === 1) {
       // A missing field in a {{foo}} constuct.
       return undefined;
     } else {
       // Someone is actually trying to call something, blow up.
-      throw new Exception("Missing helper: '" + arguments[arguments.length-1].name + "'");
+      throw new Exception('Missing helper: "' + arguments[arguments.length - 1].name + '"');
     }
   });
 
@@ -73,12 +73,12 @@ function registerDefaultHelpers(instance) {
     var inverse = options.inverse,
         fn = options.fn;
 
-    if(context === true) {
+    if (context === true) {
       return fn(this);
-    } else if(context === false || context == null) {
+    } else if (context === false || context == null) {
       return inverse(this);
     } else if (isArray(context)) {
-      if(context.length > 0) {
+      if (context.length > 0) {
         if (options.ids) {
           options.ids = [options.name];
         }
@@ -104,7 +104,7 @@ function registerDefaultHelpers(instance) {
     }
 
     var fn = options.fn, inverse = options.inverse;
-    var i = 0, ret = "", data;
+    var i = 0, ret = '', data;
 
     var contextPath;
     if (options.data && options.ids) {
@@ -117,51 +117,51 @@ function registerDefaultHelpers(instance) {
       data = createFrame(options.data);
     }
 
-    function execIteration(key, i, last) {
+    function execIteration(field, index, last) {
       if (data) {
-        data.key = key;
-        data.index = i;
-        data.first = i === 0;
-        data.last  = !!last;
+        data.key = field;
+        data.index = index;
+        data.first = index === 0;
+        data.last = !!last;
 
         if (contextPath) {
-          data.contextPath = contextPath + key;
+          data.contextPath = contextPath + field;
         }
       }
 
-      ret = ret + fn(context[key], {
+      ret = ret + fn(context[field], {
         data: data,
-        blockParams: Utils.blockParams([context[key], key], [contextPath + key, null])
+        blockParams: Utils.blockParams([context[field], field], [contextPath + field, null])
       });
     }
 
-    if(context && typeof context === 'object') {
+    if (context && typeof context === 'object') {
       if (isArray(context)) {
-        for(var j = context.length; i<j; i++) {
-          execIteration(i, i, i === context.length-1);
+        for (var j = context.length; i < j; i++) {
+          execIteration(i, i, i === context.length - 1);
         }
       } else {
         var priorKey;
 
-        for(var key in context) {
-          if(context.hasOwnProperty(key)) {
+        for (var key in context) {
+          if (context.hasOwnProperty(key)) {
             // We're running the iterations one step out of sync so we can detect
             // the last iteration without have to scan the object twice and create
-            // an itermediate keys array. 
+            // an itermediate keys array.
             if (priorKey) {
-              execIteration(priorKey, i-1);
+              execIteration(priorKey, i - 1);
             }
             priorKey = key;
             i++;
           }
         }
         if (priorKey) {
-          execIteration(priorKey, i-1, true);
+          execIteration(priorKey, i - 1, true);
         }
       }
     }
 
-    if(i === 0){
+    if (i === 0) {
       ret = inverse(this);
     }
 
@@ -194,7 +194,7 @@ function registerDefaultHelpers(instance) {
       if (options.data && options.ids) {
         var data = createFrame(options.data);
         data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]);
-        options = {data:data};
+        options = {data: data};
       }
 
       return fn(context, options);
@@ -227,15 +227,15 @@ export var logger = {
   log: function(level, message) {
     if (typeof console !== 'undefined' && logger.level <= level) {
       var method = logger.methodMap[level];
-      (console[method] || console.log).call(console, message);
+      (console[method] || console.log).call(console, message);    // eslint-disable-line no-console
     }
   }
 };
 
 export var log = logger.log;
 
-export var createFrame = function(object) {
+export function createFrame(object) {
   var frame = Utils.extend({}, object);
   frame._parent = object;
   return frame;
-};
+}
diff --git a/lib/handlebars/compiler/ast.js b/lib/handlebars/compiler/ast.js
index e5904c659..1ecf59b5e 100644
--- a/lib/handlebars/compiler/ast.js
+++ b/lib/handlebars/compiler/ast.js
@@ -27,8 +27,8 @@ var AST = {
     this.path = path;
     this.params = params || [];
     this.hash = hash;
-    this.program  = program;
-    this.inverse  = inverse;
+    this.program = program;
+    this.inverse = inverse;
 
     this.openStrip = openStrip;
     this.inverseStrip = inverseStrip;
@@ -76,8 +76,8 @@ var AST = {
 
     this.data = data;
     this.original = original;
-    this.parts    = parts;
-    this.depth    = depth;
+    this.parts = parts;
+    this.depth = depth;
   },
 
   StringLiteral: function(string, locInfo) {
@@ -130,7 +130,6 @@ var AST = {
     // a mustache is definitely a helper if:
     // * it is an eligible helper, and
     // * it has at least one parameter or hash segment
-    // TODO: Make these public utility methods
     helperExpression: function(node) {
       return !!(node.type === 'SubExpression' || node.params.length || node.hash);
     },
diff --git a/lib/handlebars/compiler/base.js b/lib/handlebars/compiler/base.js
index 167b84438..02e174fe8 100644
--- a/lib/handlebars/compiler/base.js
+++ b/lib/handlebars/compiler/base.js
@@ -1,8 +1,8 @@
-import parser from "./parser";
-import AST from "./ast";
-import WhitespaceControl from "./whitespace-control";
-module Helpers from "./helpers";
-import { extend } from "../utils";
+import parser from './parser';
+import AST from './ast';
+import WhitespaceControl from './whitespace-control';
+import * as Helpers from './helpers';
+import { extend } from '../utils';
 
 export { parser };
 
diff --git a/lib/handlebars/compiler/code-gen.js b/lib/handlebars/compiler/code-gen.js
index 92020f00e..0c40e00f0 100644
--- a/lib/handlebars/compiler/code-gen.js
+++ b/lib/handlebars/compiler/code-gen.js
@@ -1,4 +1,5 @@
-import {isArray} from "../utils";
+/*global define */
+import {isArray} from '../utils';
 
 var SourceNode;
 
@@ -56,7 +57,7 @@ function castChunk(chunk, codeGen, loc) {
     return ret;
   } else if (typeof chunk === 'boolean' || typeof chunk === 'number') {
     // Handle primitives that the SourceNode will throw up on
-    return chunk+'';
+    return chunk + '';
   }
   return chunk;
 }
@@ -90,7 +91,7 @@ CodeGen.prototype = {
   },
 
   empty: function(loc) {
-    loc = loc || this.currentLocation || {start:{}};
+    loc = loc || this.currentLocation || {start: {}};
     return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
   },
   wrap: function(chunk, loc) {
@@ -98,7 +99,7 @@ CodeGen.prototype = {
       return chunk;
     }
 
-    loc = loc || this.currentLocation || {start:{}};
+    loc = loc || this.currentLocation || {start: {}};
     chunk = castChunk(chunk, this, loc);
 
     return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk);
diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js
index a39082db1..a9bfc8564 100644
--- a/lib/handlebars/compiler/compiler.js
+++ b/lib/handlebars/compiler/compiler.js
@@ -1,6 +1,6 @@
-import Exception from "../exception";
-import {isArray, indexOf} from "../utils";
-import AST from "./ast";
+import Exception from '../exception';
+import {isArray, indexOf} from '../utils';
+import AST from './ast';
 
 var slice = [].slice;
 
@@ -67,7 +67,9 @@ Compiler.prototype = {
     };
     if (knownHelpers) {
       for (var name in knownHelpers) {
-        options.knownHelpers[name] = knownHelpers[name];
+        if (name in knownHelpers) {
+          options.knownHelpers[name] = knownHelpers[name];
+        }
       }
     }
 
@@ -75,7 +77,7 @@ Compiler.prototype = {
   },
 
   compileProgram: function(program) {
-    var result = new this.compiler().compile(program, this.options);
+    var result = new this.compiler().compile(program, this.options); // eslint-disable-line new-cap
     var guid = this.guid++;
 
     this.usePartial = this.usePartial || result.usePartial;
@@ -97,7 +99,7 @@ Compiler.prototype = {
     this.options.blockParams.unshift(program.blockParams);
 
     var body = program.body;
-    for(var i=0, l=body.length; i<l; i++) {
+    for (var i = 0, l = body.length; i < l; i++) {
       this.accept(body[i]);
     }
 
@@ -174,9 +176,9 @@ Compiler.prototype = {
   },
 
   MustacheStatement: function(mustache) {
-    this.SubExpression(mustache);
+    this.SubExpression(mustache);   // eslint-disable-line new-cap
 
-    if(mustache.escaped && !this.options.noEscape) {
+    if (mustache.escaped && !this.options.noEscape) {
       this.opcode('appendEscaped');
     } else {
       this.opcode('append');
@@ -231,7 +233,7 @@ Compiler.prototype = {
     if (this.options.knownHelpers[name]) {
       this.opcode('invokeKnownHelper', params.length, name);
     } else if (this.options.knownHelpersOnly) {
-      throw new Exception("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr);
+      throw new Exception('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr);
     } else {
       path.falsy = true;
 
@@ -250,7 +252,7 @@ Compiler.prototype = {
 
     if (blockParamId) {
       this.opcode('lookupBlockParam', blockParamId, path.parts);
-    } else  if (!name) {
+    } else if (!name) {
       // Context reference, i.e. `{{foo .}}` or `{{foo ..}}`
       this.opcode('pushContext');
     } else if (path.data) {
@@ -286,7 +288,7 @@ Compiler.prototype = {
 
     this.opcode('pushHash');
 
-    for (i=0, l=pairs.length; i<l; i++) {
+    for (i = 0, l = pairs.length; i < l; i++) {
       this.pushParam(pairs[i].value);
     }
     while (i--) {
@@ -336,13 +338,17 @@ Compiler.prototype = {
       }
     }
 
-    if (isHelper) { return 'helper'; }
-    else if (isEligible) { return 'ambiguous'; }
-    else { return 'simple'; }
+    if (isHelper) {
+      return 'helper';
+    } else if (isEligible) {
+      return 'ambiguous';
+    } else {
+      return 'simple';
+    }
   },
 
   pushParams: function(params) {
-    for(var i=0, l=params.length; i<l; i++) {
+    for (var i = 0, l = params.length; i < l; i++) {
       this.pushParam(params[i]);
     }
   },
@@ -357,7 +363,7 @@ Compiler.prototype = {
             .replace(/\//g, '.');
       }
 
-      if(val.depth) {
+      if (val.depth) {
         this.addDepth(val.depth);
       }
       this.opcode('getContext', val.depth || 0);
@@ -421,7 +427,7 @@ Compiler.prototype = {
 
 export function precompile(input, options, env) {
   if (input == null || (typeof input !== 'string' && input.type !== 'Program')) {
-    throw new Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input);
+    throw new Exception('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input);
   }
 
   options = options || {};
@@ -439,7 +445,7 @@ export function precompile(input, options, env) {
 
 export function compile(input, options, env) {
   if (input == null || (typeof input !== 'string' && input.type !== 'Program')) {
-    throw new Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
+    throw new Exception('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input);
   }
 
   options = options || {};
@@ -461,17 +467,17 @@ export function compile(input, options, env) {
   }
 
   // Template is only compiled on first use and cached after that point.
-  var ret = function(context, options) {
+  function ret(context, execOptions) {
     if (!compiled) {
       compiled = compileInput();
     }
-    return compiled.call(this, context, options);
-  };
-  ret._setup = function(options) {
+    return compiled.call(this, context, execOptions);
+  }
+  ret._setup = function(setupOptions) {
     if (!compiled) {
       compiled = compileInput();
     }
-    return compiled._setup(options);
+    return compiled._setup(setupOptions);
   };
   ret._child = function(i, data, blockParams, depths) {
     if (!compiled) {
@@ -502,6 +508,6 @@ function transformLiteralToPath(sexpr) {
     var literal = sexpr.path;
     // Casting to string here to make false and 0 literal values play nicely with the rest
     // of the system.
-    sexpr.path = new AST.PathExpression(false, 0, [literal.original+''], literal.original+'', literal.loc);
+    sexpr.path = new AST.PathExpression(false, 0, [literal.original + ''], literal.original + '', literal.loc);
   }
 }
diff --git a/lib/handlebars/compiler/helpers.js b/lib/handlebars/compiler/helpers.js
index 4a502d800..7f784adf5 100644
--- a/lib/handlebars/compiler/helpers.js
+++ b/lib/handlebars/compiler/helpers.js
@@ -1,4 +1,4 @@
-import Exception from "../exception";
+import Exception from '../exception';
 
 export function SourceLocation(source, locInfo) {
   this.source = source;
@@ -23,7 +23,7 @@ export function id(token) {
 export function stripFlags(open, close) {
   return {
     open: open.charAt(2) === '~',
-    close: close.charAt(close.length-3) === '~'
+    close: close.charAt(close.length - 3) === '~'
   };
 }
 
@@ -41,7 +41,7 @@ export function preparePath(data, parts, locInfo) {
       depth = 0,
       depthString = '';
 
-  for(var i=0,l=parts.length; i<l; i++) {
+  for (var i = 0, l = parts.length; i < l; i++) {
     var part = parts[i].part,
         // If we have [] syntax then we do not treat path references as operators,
         // i.e. foo.[this] resolves to approximately context.foo['this']
diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js
index a027edb91..e27816284 100644
--- a/lib/handlebars/compiler/javascript-compiler.js
+++ b/lib/handlebars/compiler/javascript-compiler.js
@@ -1,7 +1,7 @@
-import { COMPILER_REVISION, REVISION_CHANGES } from "../base";
-import Exception from "../exception";
-import {isArray} from "../utils";
-import CodeGen from "./code-gen";
+import { COMPILER_REVISION, REVISION_CHANGES } from '../base';
+import Exception from '../exception';
+import {isArray} from '../utils';
+import CodeGen from './code-gen';
 
 function Literal(value) {
   this.value = value;
@@ -14,7 +14,7 @@ JavaScriptCompiler.prototype = {
   // alternative compiled forms for name lookup and buffering semantics
   nameLookup: function(parent, name /* , type*/) {
     if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
-      return [parent, ".", name];
+      return [parent, '.', name];
     } else {
       return [parent, "['", name, "']"];
     }
@@ -50,7 +50,7 @@ JavaScriptCompiler.prototype = {
   },
 
   initializeBuffer: function() {
-    return this.quotedString("");
+    return this.quotedString('');
   },
   // END PUBLIC API
 
@@ -169,8 +169,8 @@ JavaScriptCompiler.prototype = {
     var varDeclarations = '';
 
     var locals = this.stackVars.concat(this.registers.list);
-    if(locals.length > 0) {
-      varDeclarations += ", " + locals.join(", ");
+    if (locals.length > 0) {
+      varDeclarations += ', ' + locals.join(', ');
     }
 
     // Generate minimizer alias mappings
@@ -180,7 +180,7 @@ JavaScriptCompiler.prototype = {
     // aliases will not be used, but this case is already being run on the client and
     // we aren't concern about minimizing the template size.
     var aliasCount = 0;
-    for (var alias in this.aliases) {
+    for (var alias in this.aliases) {    // eslint-disable-line guard-for-in
       var node = this.aliases[alias];
 
       if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) {
@@ -189,7 +189,7 @@ JavaScriptCompiler.prototype = {
       }
     }
 
-    var params = ["depth0", "helpers", "partials", "data"];
+    var params = ['depth0', 'helpers', 'partials', 'data'];
 
     if (this.useBlockParams || this.useDepths) {
       params.push('blockParams');
@@ -252,7 +252,7 @@ JavaScriptCompiler.prototype = {
         this.source.push('return "";');
       }
     } else {
-      varDeclarations += ", buffer = " + (appendFirst ? '' : this.initializeBuffer());
+      varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer());
 
       if (bufferStart) {
         bufferStart.prepend('return buffer + ');
@@ -446,6 +446,7 @@ JavaScriptCompiler.prototype = {
 
     var len = parts.length;
     for (; i < len; i++) {
+      /*eslint-disable no-loop-func */
       this.replaceStack(function(current) {
         var lookup = this.nameLookup(current, parts[i], type);
         // We want to ensure that zero and false are handled properly if the context (falsy flag)
@@ -457,6 +458,7 @@ JavaScriptCompiler.prototype = {
           return [' && ', lookup];
         }
       });
+      /*eslint-enable no-loop-func */
     }
   },
 
@@ -633,7 +635,7 @@ JavaScriptCompiler.prototype = {
         '(', lookup,
         (helper.paramsInit ? ['),(', helper.paramsInit] : []), '),',
         '(typeof helper === ', this.aliasable('"function"'), ' ? ',
-        this.source.functionCall('helper','call', helper.callParams), ' : helper))'
+        this.source.functionCall('helper', 'call', helper.callParams), ' : helper))'
     ]);
   },
 
@@ -728,9 +730,9 @@ JavaScriptCompiler.prototype = {
   compileChildren: function(environment, options) {
     var children = environment.children, child, compiler;
 
-    for(var i=0, l=children.length; i<l; i++) {
+    for (var i = 0, l = children.length; i < l; i++) {
       child = children[i];
-      compiler = new this.compiler();
+      compiler = new this.compiler();    // eslint-disable-line new-cap
 
       var index = this.matchExistingProgram(child);
 
@@ -777,7 +779,7 @@ JavaScriptCompiler.prototype = {
   },
 
   useRegister: function(name) {
-    if(!this.registers[name]) {
+    if (!this.registers[name]) {
       this.registers[name] = true;
       this.registers.list.push(name);
     }
@@ -849,11 +851,11 @@ JavaScriptCompiler.prototype = {
 
   incrStack: function() {
     this.stackSlot++;
-    if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
+    if (this.stackSlot > this.stackVars.length) { this.stackVars.push('stack' + this.stackSlot); }
     return this.topStackName();
   },
   topStackName: function() {
-    return "stack" + this.stackSlot;
+    return 'stack' + this.stackSlot;
   },
   flushInline: function() {
     var inlineStack = this.inlineStack;
@@ -1019,33 +1021,35 @@ JavaScriptCompiler.prototype = {
 };
 
 
-var reservedWords = (
-  "break else new var" +
-  " case finally return void" +
-  " catch for switch while" +
-  " continue function this with" +
-  " default if throw" +
-  " delete in try" +
-  " do instanceof typeof" +
-  " abstract enum int short" +
-  " boolean export interface static" +
-  " byte extends long super" +
-  " char final native synchronized" +
-  " class float package throws" +
-  " const goto private transient" +
-  " debugger implements protected volatile" +
-  " double import public let yield await" +
-  " null true false"
-).split(" ");
-
-var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
-
-for(var i=0, l=reservedWords.length; i<l; i++) {
-  compilerWords[reservedWords[i]] = true;
-}
+(function() {
+  var reservedWords = (
+    'break else new var' +
+    ' case finally return void' +
+    ' catch for switch while' +
+    ' continue function this with' +
+    ' default if throw' +
+    ' delete in try' +
+    ' do instanceof typeof' +
+    ' abstract enum int short' +
+    ' boolean export interface static' +
+    ' byte extends long super' +
+    ' char final native synchronized' +
+    ' class float package throws' +
+    ' const goto private transient' +
+    ' debugger implements protected volatile' +
+    ' double import public let yield await' +
+    ' null true false'
+  ).split(' ');
+
+  var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
+
+  for (var i = 0, l = reservedWords.length; i < l; i++) {
+    compilerWords[reservedWords[i]] = true;
+  }
+}());
 
 JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
-  return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name);
+  return !JavaScriptCompiler.RESERVED_WORDS[name] && (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/).test(name);
 };
 
 function strictLookup(requireTerminal, compiler, parts, type) {
diff --git a/lib/handlebars/compiler/printer.js b/lib/handlebars/compiler/printer.js
index dcc73c35c..5c708a132 100644
--- a/lib/handlebars/compiler/printer.js
+++ b/lib/handlebars/compiler/printer.js
@@ -1,4 +1,5 @@
-import Visitor from "./visitor";
+/*eslint-disable new-cap */
+import Visitor from './visitor';
 
 export function print(ast) {
   return new PrintVisitor().accept(ast);
@@ -11,13 +12,13 @@ export function PrintVisitor() {
 PrintVisitor.prototype = new Visitor();
 
 PrintVisitor.prototype.pad = function(string) {
-  var out = "";
+  var out = '';
 
-  for(var i=0,l=this.padding; i<l; i++) {
-    out = out + "  ";
+  for (var i = 0, l = this.padding; i < l; i++) {
+    out = out + '  ';
   }
 
-  out = out + string + "\n";
+  out = out + string + '\n';
   return out;
 };
 
@@ -28,14 +29,14 @@ PrintVisitor.prototype.Program = function(program) {
 
   if (program.blockParams) {
     var blockParams = 'BLOCK PARAMS: [';
-    for(i=0, l=program.blockParams.length; i<l; i++) {
+    for (i = 0, l = program.blockParams.length; i < l; i++) {
        blockParams += ' ' + program.blockParams[i];
     }
     blockParams += ' ]';
     out += this.pad(blockParams);
   }
 
-  for(i=0, l=body.length; i<l; i++) {
+  for (i = 0, l = body.length; i < l; i++) {
     out = out + this.accept(body[i]);
   }
 
@@ -49,7 +50,7 @@ PrintVisitor.prototype.MustacheStatement = function(mustache) {
 };
 
 PrintVisitor.prototype.BlockStatement = function(block) {
-  var out = "";
+  var out = '';
 
   out = out + this.pad('BLOCK:');
   this.padding++;
@@ -75,7 +76,7 @@ PrintVisitor.prototype.BlockStatement = function(block) {
 
 PrintVisitor.prototype.PartialStatement = function(partial) {
   var content = 'PARTIAL:' + partial.name.original;
-  if(partial.params[0]) {
+  if (partial.params[0]) {
     content += ' ' + this.accept(partial.params[0]);
   }
   if (partial.hash) {
@@ -95,15 +96,15 @@ PrintVisitor.prototype.CommentStatement = function(comment) {
 PrintVisitor.prototype.SubExpression = function(sexpr) {
   var params = sexpr.params, paramStrings = [], hash;
 
-  for(var i=0, l=params.length; i<l; i++) {
+  for (var i = 0, l = params.length; i < l; i++) {
     paramStrings.push(this.accept(params[i]));
   }
 
-  params = "[" + paramStrings.join(", ") + "]";
+  params = '[' + paramStrings.join(', ') + ']';
 
-  hash = sexpr.hash ? " " + this.accept(sexpr.hash) : "";
+  hash = sexpr.hash ? ' ' + this.accept(sexpr.hash) : '';
 
-  return this.accept(sexpr.path) + " " + params + hash;
+  return this.accept(sexpr.path) + ' ' + params + hash;
 };
 
 PrintVisitor.prototype.PathExpression = function(id) {
@@ -117,11 +118,11 @@ PrintVisitor.prototype.StringLiteral = function(string) {
 };
 
 PrintVisitor.prototype.NumberLiteral = function(number) {
-  return "NUMBER{" + number.value + "}";
+  return 'NUMBER{' + number.value + '}';
 };
 
 PrintVisitor.prototype.BooleanLiteral = function(bool) {
-  return "BOOLEAN{" + bool.value + "}";
+  return 'BOOLEAN{' + bool.value + '}';
 };
 
 PrintVisitor.prototype.UndefinedLiteral = function() {
@@ -136,7 +137,7 @@ PrintVisitor.prototype.Hash = function(hash) {
   var pairs = hash.pairs;
   var joinedPairs = [];
 
-  for (var i=0, l=pairs.length; i<l; i++) {
+  for (var i = 0, l = pairs.length; i < l; i++) {
     joinedPairs.push(this.accept(pairs[i]));
   }
 
@@ -145,3 +146,4 @@ PrintVisitor.prototype.Hash = function(hash) {
 PrintVisitor.prototype.HashPair = function(pair) {
   return pair.key + '=' + this.accept(pair.value);
 };
+/*eslint-enable new-cap */
diff --git a/lib/handlebars/compiler/visitor.js b/lib/handlebars/compiler/visitor.js
index b45b268e3..692a51194 100644
--- a/lib/handlebars/compiler/visitor.js
+++ b/lib/handlebars/compiler/visitor.js
@@ -1,5 +1,5 @@
-import Exception from "../exception";
-import AST from "./ast";
+import Exception from '../exception';
+import AST from './ast';
 
 function Visitor() {
   this.parents = [];
diff --git a/lib/handlebars/compiler/whitespace-control.js b/lib/handlebars/compiler/whitespace-control.js
index 97866128c..aabe45aa8 100644
--- a/lib/handlebars/compiler/whitespace-control.js
+++ b/lib/handlebars/compiler/whitespace-control.js
@@ -1,4 +1,4 @@
-import Visitor from "./visitor";
+import Visitor from './visitor';
 
 function WhitespaceControl() {
 }
@@ -38,7 +38,7 @@ WhitespaceControl.prototype.Program = function(program) {
         // If we are on a standalone node, save the indent info for partials
         if (current.type === 'PartialStatement') {
           // Pull out the whitespace from the final line
-          current.indent = (/([ \t]+$)/).exec(body[i-1].original)[1];
+          current.indent = (/([ \t]+$)/).exec(body[i - 1].original)[1];
         }
       }
     }
@@ -73,7 +73,7 @@ WhitespaceControl.prototype.BlockStatement = function(block) {
 
     // Walk the inverse chain to find the last inverse that is actually in the chain.
     while (lastInverse.chained) {
-      lastInverse = lastInverse.body[lastInverse.body.length-1].program;
+      lastInverse = lastInverse.body[lastInverse.body.length - 1].program;
     }
   }
 
@@ -108,14 +108,11 @@ WhitespaceControl.prototype.BlockStatement = function(block) {
     // Find standalone else statments
     if (isPrevWhitespace(program.body)
         && isNextWhitespace(firstInverse.body)) {
-
       omitLeft(program.body);
       omitRight(firstInverse.body);
     }
-  } else {
-    if (block.closeStrip.open) {
-      omitLeft(program.body, null, true);
-    }
+  } else if (block.closeStrip.open) {
+    omitLeft(program.body, null, true);
   }
 
   return strip;
@@ -125,7 +122,7 @@ WhitespaceControl.prototype.MustacheStatement = function(mustache) {
   return mustache.strip;
 };
 
-WhitespaceControl.prototype.PartialStatement = 
+WhitespaceControl.prototype.PartialStatement =
     WhitespaceControl.prototype.CommentStatement = function(node) {
   /* istanbul ignore next */
   var strip = node.strip || {};
@@ -144,8 +141,8 @@ function isPrevWhitespace(body, i, isRoot) {
 
   // Nodes that end with newlines are considered whitespace (but are special
   // cased for strip operations)
-  var prev = body[i-1],
-      sibling = body[i-2];
+  var prev = body[i - 1],
+      sibling = body[i - 2];
   if (!prev) {
     return isRoot;
   }
@@ -159,8 +156,8 @@ function isNextWhitespace(body, i, isRoot) {
     i = -1;
   }
 
-  var next = body[i+1],
-      sibling = body[i+2];
+  var next = body[i + 1],
+      sibling = body[i + 2];
   if (!next) {
     return isRoot;
   }
diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js
index 4e8c33ae8..f1839aa05 100644
--- a/lib/handlebars/runtime.js
+++ b/lib/handlebars/runtime.js
@@ -1,6 +1,6 @@
-module Utils from "./utils";
-import Exception from "./exception";
-import { COMPILER_REVISION, REVISION_CHANGES, createFrame } from "./base";
+import * as Utils from './utils';
+import Exception from './exception';
+import { COMPILER_REVISION, REVISION_CHANGES, createFrame } from './base';
 
 export function checkRevision(compilerInfo) {
   var compilerRevision = compilerInfo && compilerInfo[0] || 1,
@@ -10,12 +10,12 @@ export function checkRevision(compilerInfo) {
     if (compilerRevision < currentRevision) {
       var runtimeVersions = REVISION_CHANGES[currentRevision],
           compilerVersions = REVISION_CHANGES[compilerRevision];
-      throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+
-            "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").");
+      throw new Exception('Template was precompiled with an older version of Handlebars than the current runtime. ' +
+            'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
     } else {
       // Use the embedded version info since the runtime doesn't know about this revision yet
-      throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+
-            "Please update your runtime to a newer version ("+compilerInfo[1]+").");
+      throw new Exception('Template was precompiled with a newer version of Handlebars than the current runtime. ' +
+            'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
     }
   }
 }
@@ -25,7 +25,7 @@ export function checkRevision(compilerInfo) {
 export function template(templateSpec, env) {
   /* istanbul ignore next */
   if (!env) {
-    throw new Exception("No environment passed to template");
+    throw new Exception('No environment passed to template');
   }
   if (!templateSpec || !templateSpec.main) {
     throw new Exception('Unknown template object: ' + typeof templateSpec);
@@ -35,7 +35,7 @@ export function template(templateSpec, env) {
   // for external users to override these as psuedo-supported APIs.
   env.VM.checkRevision(templateSpec.compiler);
 
-  var invokePartialWrapper = function(partial, context, options) {
+  function invokePartialWrapper(partial, context, options) {
     if (options.hash) {
       context = Utils.extend({}, context, options.hash);
     }
@@ -61,9 +61,9 @@ export function template(templateSpec, env) {
       }
       return result;
     } else {
-      throw new Exception("The partial " + options.name + " could not be compiled when running in runtime-only mode");
+      throw new Exception('The partial ' + options.name + ' could not be compiled when running in runtime-only mode');
     }
-  };
+  }
 
   // Just add water
   var container = {
@@ -97,34 +97,34 @@ export function template(templateSpec, env) {
       var programWrapper = this.programs[i],
           fn = this.fn(i);
       if (data || depths || blockParams || declaredBlockParams) {
-        programWrapper = program(this, i, fn, data, declaredBlockParams, blockParams, depths);
+        programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths);
       } else if (!programWrapper) {
-        programWrapper = this.programs[i] = program(this, i, fn);
+        programWrapper = this.programs[i] = wrapProgram(this, i, fn);
       }
       return programWrapper;
     },
 
-    data: function(data, depth) {
-      while (data && depth--) {
-        data = data._parent;
+    data: function(value, depth) {
+      while (value && depth--) {
+        value = value._parent;
       }
-      return data;
+      return value;
     },
     merge: function(param, common) {
-      var ret = param || common;
+      var obj = param || common;
 
       if (param && common && (param !== common)) {
-        ret = Utils.extend({}, common, param);
+        obj = Utils.extend({}, common, param);
       }
 
-      return ret;
+      return obj;
     },
 
     noop: env.VM.noop,
     compilerInfo: templateSpec.compiler
   };
 
-  var ret = function(context, options) {
+  function ret(context, options) {
     options = options || {};
     var data = options.data;
 
@@ -139,7 +139,7 @@ export function template(templateSpec, env) {
     }
 
     return templateSpec.main.call(container, context, container.helpers, container.partials, data, blockParams, depths);
-  };
+  }
   ret.isTop = true;
 
   ret._setup = function(options) {
@@ -163,13 +163,13 @@ export function template(templateSpec, env) {
       throw new Exception('must pass parent depths');
     }
 
-    return program(container, i, templateSpec[i], data, 0, blockParams, depths);
+    return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths);
   };
   return ret;
 }
 
-export function program(container, i, fn, data, declaredBlockParams, blockParams, depths) {
-  var prog = function(context, options) {
+export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
+  function prog(context, options) {
     options = options || {};
 
     return fn.call(container,
@@ -178,7 +178,7 @@ export function program(container, i, fn, data, declaredBlockParams, blockParams
         options.data || data,
         blockParams && [options.blockParams].concat(blockParams),
         depths && [context].concat(depths));
-  };
+  }
   prog.program = i;
   prog.depth = depths ? depths.length : 0;
   prog.blockParams = declaredBlockParams || 0;
@@ -199,14 +199,14 @@ export function resolvePartial(partial, context, options) {
 export function invokePartial(partial, context, options) {
   options.partial = true;
 
-  if(partial === undefined) {
-    throw new Exception("The partial " + options.name + " could not be found");
-  } else if(partial instanceof Function) {
+  if (partial === undefined) {
+    throw new Exception('The partial ' + options.name + ' could not be found');
+  } else if (partial instanceof Function) {
     return partial(context, options);
   }
 }
 
-export function noop() { return ""; }
+export function noop() { return ''; }
 
 function initData(context, data) {
   if (!data || !('root' in data)) {
diff --git a/lib/handlebars/safe-string.js b/lib/handlebars/safe-string.js
index a6b8ecf20..468019421 100644
--- a/lib/handlebars/safe-string.js
+++ b/lib/handlebars/safe-string.js
@@ -4,7 +4,7 @@ function SafeString(string) {
 }
 
 SafeString.prototype.toString = SafeString.prototype.toHTML = function() {
-  return "" + this.string;
+  return '' + this.string;
 };
 
 export default SafeString;
diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js
index 41495e1bf..07e9b7784 100644
--- a/lib/handlebars/utils.js
+++ b/lib/handlebars/utils.js
@@ -1,11 +1,11 @@
 /*jshint -W004 */
 var escape = {
-  "&": "&amp;",
-  "<": "&lt;",
-  ">": "&gt;",
-  '"': "&quot;",
-  "'": "&#x27;",
-  "`": "&#x60;"
+  '&': '&amp;',
+  '<': '&lt;',
+  '>': '&gt;',
+  '"': '&quot;',
+  "'": '&#x27;',
+  '`': '&#x60;'
 };
 
 var badChars = /[&<>"'`]/g;
@@ -31,6 +31,7 @@ export var toString = Object.prototype.toString;
 
 // Sourced from lodash
 // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
+/*eslint-disable func-style */
 var isFunction = function(value) {
   return typeof value === 'function';
 };
@@ -42,6 +43,7 @@ if (isFunction(/x/)) {
   };
 }
 export var isFunction;
+/*eslint-enable func-style */
 
 /* istanbul ignore next */
 export var isArray = Array.isArray || function(value) {
diff --git a/lib/index.js b/lib/index.js
index 8213d14e5..ac559674a 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -3,7 +3,7 @@
 
 // var local = handlebars.create();
 
-var handlebars = require('../dist/cjs/handlebars')["default"];
+var handlebars = require('../dist/cjs/handlebars')['default'];
 
 var printer = require('../dist/cjs/handlebars/compiler/printer');
 handlebars.PrintVisitor = printer.PrintVisitor;
@@ -12,13 +12,13 @@ handlebars.print = printer.print;
 module.exports = handlebars;
 
 // Publish a Node.js require() handler for .handlebars and .hbs files
+function extension(module, filename) {
+  var fs = require('fs');
+  var templateString = fs.readFileSync(filename, 'utf8');
+  module.exports = handlebars.compile(templateString);
+}
 /* istanbul ignore else */
 if (typeof require !== 'undefined' && require.extensions) {
-  var extension = function(module, filename) {
-    var fs = require("fs");
-    var templateString = fs.readFileSync(filename, "utf8");
-    module.exports = handlebars.compile(templateString);
-  };
-  require.extensions[".handlebars"] = extension;
-  require.extensions[".hbs"] = extension;
+  require.extensions['.handlebars'] = extension;
+  require.extensions['.hbs'] = extension;
 }
diff --git a/lib/precompiler.js b/lib/precompiler.js
index f67347984..f0955e7ff 100644
--- a/lib/precompiler.js
+++ b/lib/precompiler.js
@@ -1,4 +1,4 @@
-
+/*eslint-disable no-console */
 var fs = require('fs'),
     Handlebars = require('./index'),
     basename = require('path').basename,
@@ -70,10 +70,10 @@ module.exports.cli = function(opts) {
         stat = fs.statSync(path);
     if (stat.isDirectory()) {
       fs.readdirSync(template).map(function(file) {
-        var path = template + '/' + file;
+        var childPath = template + '/' + file;
 
-        if (extension.test(path) || fs.statSync(path).isDirectory()) {
-          processTemplate(path, root || template);
+        if (extension.test(childPath) || fs.statSync(childPath).isDirectory()) {
+          processTemplate(childPath, root || template);
         }
       });
     } else {
@@ -99,7 +99,7 @@ module.exports.cli = function(opts) {
       if (!root) {
         template = basename(template);
       } else if (template.indexOf(root) === 0) {
-        template = template.substring(root.length+1);
+        template = template.substring(root.length + 1);
       }
       template = template.replace(extension, '');
 
@@ -114,12 +114,12 @@ module.exports.cli = function(opts) {
       if (opts.simple) {
         output.add([precompiled, '\n']);
       } else if (opts.partial) {
-        if(opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
+        if (opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
           output.add('return ');
         }
         output.add(['Handlebars.partials[\'', template, '\'] = template(', precompiled, ');\n']);
       } else {
-        if(opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
+        if (opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
           output.add('return ');
         }
         output.add(['templates[\'', template, '\'] = template(', precompiled, ');\n']);
@@ -134,8 +134,8 @@ module.exports.cli = function(opts) {
   // Output the content
   if (!opts.simple) {
     if (opts.amd) {
-      if(opts.templates.length > 1 || (opts.templates.length == 1 && fs.statSync(opts.templates[0]).isDirectory())) {
-        if(opts.partial){
+      if (opts.templates.length > 1 || (opts.templates.length == 1 && fs.statSync(opts.templates[0]).isDirectory())) {
+        if (opts.partial) {
           output.add('return Handlebars.partials;\n');
         } else {
           output.add('return templates;\n');
diff --git a/package.json b/package.json
index f653a3f89..b23b783dd 100644
--- a/package.json
+++ b/package.json
@@ -30,11 +30,13 @@
   "devDependencies": {
     "async": "^0.9.0",
     "aws-sdk": "~1.5.0",
+    "babel-loader": "^5.0.0",
+    "babel-runtime": "^5.1.10",
     "benchmark": "~1.0",
     "dustjs-linkedin": "^2.0.2",
     "eco": "~1.1.0-rc-3",
-    "es6-module-packager": "^2.0.0",
     "grunt": "~0.4.1",
+    "grunt-babel": "^5.0.0",
     "grunt-cli": "~0.1.10",
     "grunt-contrib-clean": "0.x",
     "grunt-contrib-concat": "0.x",
@@ -44,7 +46,9 @@
     "grunt-contrib-requirejs": "0.x",
     "grunt-contrib-uglify": "0.x",
     "grunt-contrib-watch": "0.x",
+    "grunt-eslint": "^11.0.0",
     "grunt-saucelabs": "8.x",
+    "grunt-webpack": "^1.0.8",
     "istanbul": "^0.3.0",
     "jison": "~0.3.0",
     "keen.io": "0.0.3",
diff --git a/spec/.eslintrc b/spec/.eslintrc
new file mode 100644
index 000000000..2d0581468
--- /dev/null
+++ b/spec/.eslintrc
@@ -0,0 +1,34 @@
+{
+  "globals": {
+    "CompilerContext": true,
+    "Handlebars": true,
+    "handlebarsEnv": true,
+
+    "shouldCompileTo": true,
+    "shouldCompileToWithPartials": true,
+    "shouldThrow": true,
+    "compileWithPartials": true,
+
+    "console": true,
+    "require": true,
+    "suite": true,
+    "equal": true,
+    "equals": true,
+    "test": true,
+    "testBoth": true,
+    "raises": true,
+    "deepEqual": true,
+    "start": true,
+    "stop": true,
+    "ok": true,
+    "strictEqual": true,
+    "define": true
+  },
+  "env": {
+    "mocha": true
+  },
+  "rules": {
+    // Disabling for tests, for now.
+    "no-path-concat": 0
+  }
+}
\ No newline at end of file
diff --git a/spec/ast.js b/spec/ast.js
index 3b2a4ae20..6f492fddd 100644
--- a/spec/ast.js
+++ b/spec/ast.js
@@ -1,4 +1,3 @@
-/*global Handlebars, handlebarsEnv, shouldThrow */
 describe('ast', function() {
   if (!Handlebars.AST) {
     return;
@@ -15,7 +14,7 @@ describe('ast', function() {
     }
   };
 
-  function testLocationInfoStorage(node){
+  function testLocationInfoStorage(node) {
     equals(node.loc.start.line, 1);
     equals(node.loc.start.column, 1);
     equals(node.loc.end.line, 1);
@@ -24,9 +23,7 @@ describe('ast', function() {
 
   describe('MustacheStatement', function() {
     it('should store args', function() {
-      var id = {isSimple: true},
-          hash = {},
-          mustache = new handlebarsEnv.AST.MustacheStatement({}, null, null, true, {}, LOCATION_INFO);
+      var mustache = new handlebarsEnv.AST.MustacheStatement({}, null, null, true, {}, LOCATION_INFO);
       equals(mustache.type, 'MustacheStatement');
       equals(mustache.escaped, true);
       testLocationInfoStorage(mustache);
@@ -35,11 +32,11 @@ describe('ast', function() {
   describe('BlockStatement', function() {
     it('should throw on mustache mismatch', function() {
       shouldThrow(function() {
-        handlebarsEnv.parse("\n  {{#foo}}{{/bar}}");
+        handlebarsEnv.parse('\n  {{#foo}}{{/bar}}');
       }, Handlebars.Exception, "foo doesn't match bar - 2:5");
     });
 
-    it('stores location info', function(){
+    it('stores location info', function() {
       var mustacheNode = new handlebarsEnv.AST.MustacheStatement([{ original: 'foo'}], null, null, false, {});
       var block = new handlebarsEnv.AST.BlockStatement(
             mustacheNode,
@@ -54,114 +51,114 @@ describe('ast', function() {
     });
   });
   describe('PathExpression', function() {
-    it('stores location info', function(){
+    it('stores location info', function() {
       var idNode = new handlebarsEnv.AST.PathExpression(false, 0, [], 'foo', LOCATION_INFO);
       testLocationInfoStorage(idNode);
     });
   });
 
-  describe('Hash', function(){
-    it('stores location info', function(){
+  describe('Hash', function() {
+    it('stores location info', function() {
       var hash = new handlebarsEnv.AST.Hash([], LOCATION_INFO);
       testLocationInfoStorage(hash);
     });
   });
 
-  describe('ContentStatement', function(){
-    it('stores location info', function(){
-      var content = new handlebarsEnv.AST.ContentStatement("HI", LOCATION_INFO);
+  describe('ContentStatement', function() {
+    it('stores location info', function() {
+      var content = new handlebarsEnv.AST.ContentStatement('HI', LOCATION_INFO);
       testLocationInfoStorage(content);
     });
   });
 
-  describe('CommentStatement', function(){
-    it('stores location info', function(){
-      var comment = new handlebarsEnv.AST.CommentStatement("HI", {}, LOCATION_INFO);
+  describe('CommentStatement', function() {
+    it('stores location info', function() {
+      var comment = new handlebarsEnv.AST.CommentStatement('HI', {}, LOCATION_INFO);
       testLocationInfoStorage(comment);
     });
   });
 
-  describe('NumberLiteral', function(){
-    it('stores location info', function(){
-      var integer = new handlebarsEnv.AST.NumberLiteral("6", LOCATION_INFO);
+  describe('NumberLiteral', function() {
+    it('stores location info', function() {
+      var integer = new handlebarsEnv.AST.NumberLiteral('6', LOCATION_INFO);
       testLocationInfoStorage(integer);
     });
   });
 
-  describe('StringLiteral', function(){
-    it('stores location info', function(){
-      var string = new handlebarsEnv.AST.StringLiteral("6", LOCATION_INFO);
+  describe('StringLiteral', function() {
+    it('stores location info', function() {
+      var string = new handlebarsEnv.AST.StringLiteral('6', LOCATION_INFO);
       testLocationInfoStorage(string);
     });
   });
 
-  describe('BooleanLiteral', function(){
-    it('stores location info', function(){
-      var bool = new handlebarsEnv.AST.BooleanLiteral("true", LOCATION_INFO);
+  describe('BooleanLiteral', function() {
+    it('stores location info', function() {
+      var bool = new handlebarsEnv.AST.BooleanLiteral('true', LOCATION_INFO);
       testLocationInfoStorage(bool);
     });
   });
 
-  describe('PartialStatement', function(){
-    it('stores location info', function(){
+  describe('PartialStatement', function() {
+    it('stores location info', function() {
       var pn = new handlebarsEnv.AST.PartialStatement('so_partial', [], {}, {}, LOCATION_INFO);
       testLocationInfoStorage(pn);
     });
   });
 
-  describe('Program', function(){
-    it('storing location info', function(){
+  describe('Program', function() {
+    it('storing location info', function() {
       var pn = new handlebarsEnv.AST.Program([], null, {}, LOCATION_INFO);
       testLocationInfoStorage(pn);
     });
   });
 
-  describe("Line Numbers", function(){
+  describe('Line Numbers', function() {
     var ast, body;
 
-    function testColumns(node, firstLine, lastLine, firstColumn, lastColumn){
+    function testColumns(node, firstLine, lastLine, firstColumn, lastColumn) {
       equals(node.loc.start.line, firstLine);
       equals(node.loc.start.column, firstColumn);
       equals(node.loc.end.line, lastLine);
       equals(node.loc.end.column, lastColumn);
     }
 
-    ast = Handlebars.parse("line 1 {{line1Token}}\n line 2 {{line2token}}\n line 3 {{#blockHelperOnLine3}}\nline 4{{line4token}}\n" +
-                           "line5{{else}}\n{{line6Token}}\n{{/blockHelperOnLine3}}");
+    ast = Handlebars.parse('line 1 {{line1Token}}\n line 2 {{line2token}}\n line 3 {{#blockHelperOnLine3}}\nline 4{{line4token}}\n' +
+                           'line5{{else}}\n{{line6Token}}\n{{/blockHelperOnLine3}}');
     body = ast.body;
 
-    it('gets ContentNode line numbers', function(){
+    it('gets ContentNode line numbers', function() {
       var contentNode = body[0];
       testColumns(contentNode, 1, 1, 0, 7);
     });
 
-    it('gets MustacheStatement line numbers', function(){
+    it('gets MustacheStatement line numbers', function() {
       var mustacheNode = body[1];
       testColumns(mustacheNode, 1, 1, 7, 21);
     });
 
-    it('gets line numbers correct when newlines appear', function(){
+    it('gets line numbers correct when newlines appear', function() {
       testColumns(body[2], 1, 2, 21, 8);
     });
 
-    it('gets MustacheStatement line numbers correct across newlines', function(){
+    it('gets MustacheStatement line numbers correct across newlines', function() {
       var secondMustacheStatement = body[3];
       testColumns(secondMustacheStatement, 2, 2, 8, 22);
      });
 
-     it('gets the block helper information correct', function(){
+     it('gets the block helper information correct', function() {
        var blockHelperNode = body[5];
        testColumns(blockHelperNode, 3, 7, 8, 23);
      });
 
-     it('correctly records the line numbers the program of a block helper', function(){
+     it('correctly records the line numbers the program of a block helper', function() {
        var blockHelperNode = body[5],
            program = blockHelperNode.program;
 
        testColumns(program, 3, 5, 8, 5);
      });
 
-     it('correctly records the line numbers of an inverse of a block helper', function(){
+     it('correctly records the line numbers of an inverse of a block helper', function() {
        var blockHelperNode = body[5],
            inverse = blockHelperNode.inverse;
 
@@ -169,7 +166,7 @@ describe('ast', function() {
      });
   });
 
-  describe('standalone flags', function(){
+  describe('standalone flags', function() {
     describe('mustache', function() {
       it('does not mark mustaches as standalone', function() {
         var ast = Handlebars.parse('  {{comment}} ');
diff --git a/spec/basic.js b/spec/basic.js
index 323a103fc..f9b781b4a 100644
--- a/spec/basic.js
+++ b/spec/basic.js
@@ -1,38 +1,37 @@
-/*global CompilerContext, Handlebars, beforeEach, shouldCompileTo, shouldThrow */
 global.handlebarsEnv = null;
 
 beforeEach(function() {
   global.handlebarsEnv = Handlebars.create();
 });
 
-describe("basic context", function() {
-  it("most basic", function() {
-    shouldCompileTo("{{foo}}", { foo: "foo" }, "foo");
+describe('basic context', function() {
+  it('most basic', function() {
+    shouldCompileTo('{{foo}}', { foo: 'foo' }, 'foo');
   });
 
-  it("escaping", function() {
-    shouldCompileTo("\\{{foo}}", { foo: "food" }, "{{foo}}");
-    shouldCompileTo("content \\{{foo}}", { foo: "food" }, "content {{foo}}");
-    shouldCompileTo("\\\\{{foo}}", { foo: "food" }, "\\food");
-    shouldCompileTo("content \\\\{{foo}}", { foo: "food" }, "content \\food");
-    shouldCompileTo("\\\\ {{foo}}", { foo: "food" }, "\\\\ food");
+  it('escaping', function() {
+    shouldCompileTo('\\{{foo}}', { foo: 'food' }, '{{foo}}');
+    shouldCompileTo('content \\{{foo}}', { foo: 'food' }, 'content {{foo}}');
+    shouldCompileTo('\\\\{{foo}}', { foo: 'food' }, '\\food');
+    shouldCompileTo('content \\\\{{foo}}', { foo: 'food' }, 'content \\food');
+    shouldCompileTo('\\\\ {{foo}}', { foo: 'food' }, '\\\\ food');
   });
 
-  it("compiling with a basic context", function() {
-    shouldCompileTo("Goodbye\n{{cruel}}\n{{world}}!", {cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!",
-                    "It works if all the required keys are provided");
+  it('compiling with a basic context', function() {
+    shouldCompileTo('Goodbye\n{{cruel}}\n{{world}}!', {cruel: 'cruel', world: 'world'}, 'Goodbye\ncruel\nworld!',
+                    'It works if all the required keys are provided');
   });
 
-  it("compiling with an undefined context", function() {
-    shouldCompileTo("Goodbye\n{{cruel}}\n{{world.bar}}!", undefined, "Goodbye\n\n!");
+  it('compiling with an undefined context', function() {
+    shouldCompileTo('Goodbye\n{{cruel}}\n{{world.bar}}!', undefined, 'Goodbye\n\n!');
 
-    shouldCompileTo("{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}", undefined, "Goodbye");
+    shouldCompileTo('{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}', undefined, 'Goodbye');
   });
 
-  it("comments", function() {
-    shouldCompileTo("{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!",
-      {cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!",
-      "comments are ignored");
+  it('comments', function() {
+    shouldCompileTo('{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!',
+      {cruel: 'cruel', world: 'world'}, 'Goodbye\ncruel\nworld!',
+      'comments are ignored');
 
     shouldCompileTo('    {{~! comment ~}}      blah', {}, 'blah');
     shouldCompileTo('    {{~!-- long-comment --~}}      blah', {}, 'blah');
@@ -42,28 +41,30 @@ describe("basic context", function() {
     shouldCompileTo('    {{~!-- long-comment --}}      blah', {}, '      blah');
   });
 
-  it("boolean", function() {
-    var string   = "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!";
-    shouldCompileTo(string, {goodbye: true, world: "world"}, "GOODBYE cruel world!",
-                    "booleans show the contents when true");
+  it('boolean', function() {
+    var string = '{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!';
+    shouldCompileTo(string, {goodbye: true, world: 'world'}, 'GOODBYE cruel world!',
+                    'booleans show the contents when true');
 
-    shouldCompileTo(string, {goodbye: false, world: "world"}, "cruel world!",
-                    "booleans do not show the contents when false");
+    shouldCompileTo(string, {goodbye: false, world: 'world'}, 'cruel world!',
+                    'booleans do not show the contents when false');
   });
 
-  it("zeros", function() {
-    shouldCompileTo("num1: {{num1}}, num2: {{num2}}", {num1: 42, num2: 0},
-        "num1: 42, num2: 0");
-    shouldCompileTo("num: {{.}}", 0, "num: 0");
-    shouldCompileTo("num: {{num1/num2}}", {num1: {num2: 0}}, "num: 0");
+  it('zeros', function() {
+    shouldCompileTo('num1: {{num1}}, num2: {{num2}}', {num1: 42, num2: 0},
+        'num1: 42, num2: 0');
+    shouldCompileTo('num: {{.}}', 0, 'num: 0');
+    shouldCompileTo('num: {{num1/num2}}', {num1: {num2: 0}}, 'num: 0');
   });
   it('false', function() {
+    /*eslint-disable no-new-wrappers */
     shouldCompileTo('val1: {{val1}}, val2: {{val2}}', {val1: false, val2: new Boolean(false)}, 'val1: false, val2: false');
     shouldCompileTo('val: {{.}}', false, 'val: false');
     shouldCompileTo('val: {{val1/val2}}', {val1: {val2: false}}, 'val: false');
 
     shouldCompileTo('val1: {{{val1}}}, val2: {{{val2}}}', {val1: false, val2: new Boolean(false)}, 'val1: false, val2: false');
     shouldCompileTo('val: {{{val1/val2}}}', {val1: {val2: false}}, 'val: false');
+    /*eslint-enable */
   });
 
   it('should handle undefined and null', function() {
@@ -90,143 +91,143 @@ describe("basic context", function() {
         'null!');
   });
 
-  it("newlines", function() {
+  it('newlines', function() {
       shouldCompileTo("Alan's\nTest", {}, "Alan's\nTest");
       shouldCompileTo("Alan's\rTest", {}, "Alan's\rTest");
   });
 
-  it("escaping text", function() {
+  it('escaping text', function() {
     shouldCompileTo("Awesome's", {}, "Awesome's", "text is escaped so that it doesn't get caught on single quotes");
-    shouldCompileTo("Awesome\\", {}, "Awesome\\", "text is escaped so that the closing quote can't be ignored");
-    shouldCompileTo("Awesome\\\\ foo", {}, "Awesome\\\\ foo", "text is escaped so that it doesn't mess up backslashes");
-    shouldCompileTo("Awesome {{foo}}", {foo: '\\'}, "Awesome \\", "text is escaped so that it doesn't mess up backslashes");
-    shouldCompileTo(' " " ', {}, ' " " ', "double quotes never produce invalid javascript");
+    shouldCompileTo('Awesome\\', {}, 'Awesome\\', "text is escaped so that the closing quote can't be ignored");
+    shouldCompileTo('Awesome\\\\ foo', {}, 'Awesome\\\\ foo', "text is escaped so that it doesn't mess up backslashes");
+    shouldCompileTo('Awesome {{foo}}', {foo: '\\'}, 'Awesome \\', "text is escaped so that it doesn't mess up backslashes");
+    shouldCompileTo(" ' ' ", {}, " ' ' ", 'double quotes never produce invalid javascript');
   });
 
-  it("escaping expressions", function() {
-   shouldCompileTo("{{{awesome}}}", {awesome: "&\"\\<>"}, '&\"\\<>',
+  it('escaping expressions', function() {
+   shouldCompileTo('{{{awesome}}}', {awesome: '&\'\\<>'}, '&\'\\<>',
           "expressions with 3 handlebars aren't escaped");
 
-   shouldCompileTo("{{&awesome}}", {awesome: "&\"\\<>"}, '&\"\\<>',
+   shouldCompileTo('{{&awesome}}', {awesome: '&\'\\<>'}, '&\'\\<>',
           "expressions with {{& handlebars aren't escaped");
 
-   shouldCompileTo("{{awesome}}", {awesome: "&\"'`\\<>"}, '&amp;&quot;&#x27;&#x60;\\&lt;&gt;',
-          "by default expressions should be escaped");
+   shouldCompileTo('{{awesome}}', {awesome: "&\"'`\\<>"}, '&amp;&quot;&#x27;&#x60;\\&lt;&gt;',
+          'by default expressions should be escaped');
 
-   shouldCompileTo("{{awesome}}", {awesome: "Escaped, <b> looks like: &lt;b&gt;"}, 'Escaped, &lt;b&gt; looks like: &amp;lt;b&amp;gt;',
-          "escaping should properly handle amperstands");
+   shouldCompileTo('{{awesome}}', {awesome: 'Escaped, <b> looks like: &lt;b&gt;'}, 'Escaped, &lt;b&gt; looks like: &amp;lt;b&amp;gt;',
+          'escaping should properly handle amperstands');
   });
 
   it("functions returning safestrings shouldn't be escaped", function() {
-    var hash = {awesome: function() { return new Handlebars.SafeString("&\"\\<>"); }};
-    shouldCompileTo("{{awesome}}", hash, '&\"\\<>',
+    var hash = {awesome: function() { return new Handlebars.SafeString('&\'\\<>'); }};
+    shouldCompileTo('{{awesome}}', hash, '&\'\\<>',
         "functions returning safestrings aren't escaped");
   });
 
-  it("functions", function() {
-    shouldCompileTo("{{awesome}}", {awesome: function() { return "Awesome"; }}, "Awesome",
-                    "functions are called and render their output");
-    shouldCompileTo("{{awesome}}", {awesome: function() { return this.more; }, more:  "More awesome"}, "More awesome",
-                    "functions are bound to the context");
+  it('functions', function() {
+    shouldCompileTo('{{awesome}}', {awesome: function() { return 'Awesome'; }}, 'Awesome',
+                    'functions are called and render their output');
+    shouldCompileTo('{{awesome}}', {awesome: function() { return this.more; }, more: 'More awesome'}, 'More awesome',
+                    'functions are bound to the context');
   });
 
-  it("functions with context argument", function() {
-    shouldCompileTo("{{awesome frank}}",
+  it('functions with context argument', function() {
+    shouldCompileTo('{{awesome frank}}',
         {awesome: function(context) { return context; },
-          frank: "Frank"},
-        "Frank", "functions are called with context arguments");
+          frank: 'Frank'},
+        'Frank', 'functions are called with context arguments');
   });
-  it("pathed functions with context argument", function() {
-    shouldCompileTo("{{bar.awesome frank}}",
+  it('pathed functions with context argument', function() {
+    shouldCompileTo('{{bar.awesome frank}}',
         {bar: {awesome: function(context) { return context; }},
-          frank: "Frank"},
-        "Frank", "functions are called with context arguments");
+          frank: 'Frank'},
+        'Frank', 'functions are called with context arguments');
   });
-  it("depthed functions with context argument", function() {
-    shouldCompileTo("{{#with frank}}{{../awesome .}}{{/with}}",
+  it('depthed functions with context argument', function() {
+    shouldCompileTo('{{#with frank}}{{../awesome .}}{{/with}}',
         {awesome: function(context) { return context; },
-          frank: "Frank"},
-        "Frank", "functions are called with context arguments");
+          frank: 'Frank'},
+        'Frank', 'functions are called with context arguments');
   });
 
-  it("block functions with context argument", function() {
-    shouldCompileTo("{{#awesome 1}}inner {{.}}{{/awesome}}",
+  it('block functions with context argument', function() {
+    shouldCompileTo('{{#awesome 1}}inner {{.}}{{/awesome}}',
         {awesome: function(context, options) { return options.fn(context); }},
-        "inner 1", "block functions are called with context and options");
+        'inner 1', 'block functions are called with context and options');
   });
 
-  it("depthed block functions with context argument", function() {
-    shouldCompileTo("{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}",
+  it('depthed block functions with context argument', function() {
+    shouldCompileTo('{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}',
         {value: true, awesome: function(context, options) { return options.fn(context); }},
-        "inner 1", "block functions are called with context and options");
+        'inner 1', 'block functions are called with context and options');
   });
 
-  it("block functions without context argument", function() {
-    shouldCompileTo("{{#awesome}}inner{{/awesome}}",
+  it('block functions without context argument', function() {
+    shouldCompileTo('{{#awesome}}inner{{/awesome}}',
         {awesome: function(options) { return options.fn(this); }},
-        "inner", "block functions are called with options");
+        'inner', 'block functions are called with options');
   });
-  it("pathed block functions without context argument", function() {
-    shouldCompileTo("{{#foo.awesome}}inner{{/foo.awesome}}",
+  it('pathed block functions without context argument', function() {
+    shouldCompileTo('{{#foo.awesome}}inner{{/foo.awesome}}',
         {foo: {awesome: function() { return this; }}},
-        "inner", "block functions are called with options");
+        'inner', 'block functions are called with options');
   });
-  it("depthed block functions without context argument", function() {
-    shouldCompileTo("{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}",
+  it('depthed block functions without context argument', function() {
+    shouldCompileTo('{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}',
         {value: true, awesome: function() { return this; }},
-        "inner", "block functions are called with options");
+        'inner', 'block functions are called with options');
   });
 
 
-  it("paths with hyphens", function() {
-    shouldCompileTo("{{foo-bar}}", {"foo-bar": "baz"}, "baz", "Paths can contain hyphens (-)");
-    shouldCompileTo("{{foo.foo-bar}}", {foo: {"foo-bar": "baz"}}, "baz", "Paths can contain hyphens (-)");
-    shouldCompileTo("{{foo/foo-bar}}", {foo: {"foo-bar": "baz"}}, "baz", "Paths can contain hyphens (-)");
+  it('paths with hyphens', function() {
+    shouldCompileTo('{{foo-bar}}', {'foo-bar': 'baz'}, 'baz', 'Paths can contain hyphens (-)');
+    shouldCompileTo('{{foo.foo-bar}}', {foo: {'foo-bar': 'baz'}}, 'baz', 'Paths can contain hyphens (-)');
+    shouldCompileTo('{{foo/foo-bar}}', {foo: {'foo-bar': 'baz'}}, 'baz', 'Paths can contain hyphens (-)');
   });
 
-  it("nested paths", function() {
-    shouldCompileTo("Goodbye {{alan/expression}} world!", {alan: {expression: "beautiful"}},
-                    "Goodbye beautiful world!", "Nested paths access nested objects");
+  it('nested paths', function() {
+    shouldCompileTo('Goodbye {{alan/expression}} world!', {alan: {expression: 'beautiful'}},
+                    'Goodbye beautiful world!', 'Nested paths access nested objects');
   });
 
-  it("nested paths with empty string value", function() {
-    shouldCompileTo("Goodbye {{alan/expression}} world!", {alan: {expression: ""}},
-                    "Goodbye  world!", "Nested paths access nested objects with empty string");
+  it('nested paths with empty string value', function() {
+    shouldCompileTo('Goodbye {{alan/expression}} world!', {alan: {expression: ''}},
+                    'Goodbye  world!', 'Nested paths access nested objects with empty string');
   });
 
-  it("literal paths", function() {
-    shouldCompileTo("Goodbye {{[@alan]/expression}} world!", {"@alan": {expression: "beautiful"}},
-        "Goodbye beautiful world!", "Literal paths can be used");
-    shouldCompileTo("Goodbye {{[foo bar]/expression}} world!", {"foo bar": {expression: "beautiful"}},
-        "Goodbye beautiful world!", "Literal paths can be used");
+  it('literal paths', function() {
+    shouldCompileTo('Goodbye {{[@alan]/expression}} world!', {'@alan': {expression: 'beautiful'}},
+        'Goodbye beautiful world!', 'Literal paths can be used');
+    shouldCompileTo('Goodbye {{[foo bar]/expression}} world!', {'foo bar': {expression: 'beautiful'}},
+        'Goodbye beautiful world!', 'Literal paths can be used');
   });
 
   it('literal references', function() {
-    shouldCompileTo("Goodbye {{[foo bar]}} world!", {"foo bar": "beautiful"},
-        "Goodbye beautiful world!", "Literal paths can be used");
+    shouldCompileTo('Goodbye {{[foo bar]}} world!', {'foo bar': 'beautiful'},
+        'Goodbye beautiful world!', 'Literal paths can be used');
   });
 
   it("that current context path ({{.}}) doesn't hit helpers", function() {
-    shouldCompileTo("test: {{.}}", [null, {helper: "awesome"}], "test: ");
+    shouldCompileTo('test: {{.}}', [null, {helper: 'awesome'}], 'test: ');
   });
 
-  it("complex but empty paths", function() {
-    shouldCompileTo("{{person/name}}", {person: {name: null}}, "");
-    shouldCompileTo("{{person/name}}", {person: {}}, "");
+  it('complex but empty paths', function() {
+    shouldCompileTo('{{person/name}}', {person: {name: null}}, '');
+    shouldCompileTo('{{person/name}}', {person: {}}, '');
   });
 
-  it("this keyword in paths", function() {
-    var string = "{{#goodbyes}}{{this}}{{/goodbyes}}";
-    var hash = {goodbyes: ["goodbye", "Goodbye", "GOODBYE"]};
-    shouldCompileTo(string, hash, "goodbyeGoodbyeGOODBYE",
-      "This keyword in paths evaluates to current context");
+  it('this keyword in paths', function() {
+    var string = '{{#goodbyes}}{{this}}{{/goodbyes}}';
+    var hash = {goodbyes: ['goodbye', 'Goodbye', 'GOODBYE']};
+    shouldCompileTo(string, hash, 'goodbyeGoodbyeGOODBYE',
+      'This keyword in paths evaluates to current context');
 
-    string = "{{#hellos}}{{this/text}}{{/hellos}}";
-    hash = {hellos: [{text: "hello"}, {text: "Hello"}, {text: "HELLO"}]};
-    shouldCompileTo(string, hash, "helloHelloHELLO", "This keyword evaluates in more complex paths");
+    string = '{{#hellos}}{{this/text}}{{/hellos}}';
+    hash = {hellos: [{text: 'hello'}, {text: 'Hello'}, {text: 'HELLO'}]};
+    shouldCompileTo(string, hash, 'helloHelloHELLO', 'This keyword evaluates in more complex paths');
   });
 
-  it("this keyword nested inside path", function() {
+  it('this keyword nested inside path', function() {
     shouldThrow(function() {
       CompilerContext.compile('{{#hellos}}{{text/this/foo}}{{/hellos}}');
     }, Error, 'Invalid path: text/this - 1:13');
@@ -235,22 +236,22 @@ describe("basic context", function() {
     shouldCompileTo('{{text/[this]}}', {text: {'this': 'bar'}}, 'bar');
   });
 
-  it("this keyword in helpers", function() {
+  it('this keyword in helpers', function() {
     var helpers = {foo: function(value) {
         return 'bar ' + value;
     }};
-    var string = "{{#goodbyes}}{{foo this}}{{/goodbyes}}";
-    var hash = {goodbyes: ["goodbye", "Goodbye", "GOODBYE"]};
-    shouldCompileTo(string, [hash, helpers], "bar goodbyebar Goodbyebar GOODBYE",
-      "This keyword in paths evaluates to current context");
+    var string = '{{#goodbyes}}{{foo this}}{{/goodbyes}}';
+    var hash = {goodbyes: ['goodbye', 'Goodbye', 'GOODBYE']};
+    shouldCompileTo(string, [hash, helpers], 'bar goodbyebar Goodbyebar GOODBYE',
+      'This keyword in paths evaluates to current context');
 
-    string = "{{#hellos}}{{foo this/text}}{{/hellos}}";
-    hash = {hellos: [{text: "hello"}, {text: "Hello"}, {text: "HELLO"}]};
-    shouldCompileTo(string, [hash, helpers], "bar hellobar Hellobar HELLO", "This keyword evaluates in more complex paths");
+    string = '{{#hellos}}{{foo this/text}}{{/hellos}}';
+    hash = {hellos: [{text: 'hello'}, {text: 'Hello'}, {text: 'HELLO'}]};
+    shouldCompileTo(string, [hash, helpers], 'bar hellobar Hellobar HELLO', 'This keyword evaluates in more complex paths');
   });
 
-  it("this keyword nested inside helpers param", function() {
-    var string = "{{#hellos}}{{foo text/this/foo}}{{/hellos}}";
+  it('this keyword nested inside helpers param', function() {
+    var string = '{{#hellos}}{{foo text/this/foo}}{{/hellos}}';
     shouldThrow(function() {
       CompilerContext.compile(string);
     }, Error, 'Invalid path: text/this - 1:17');
diff --git a/spec/blocks.js b/spec/blocks.js
index 21fb71842..80f1580e6 100644
--- a/spec/blocks.js
+++ b/spec/blocks.js
@@ -1,112 +1,111 @@
-/*global CompilerContext, shouldCompileTo, shouldThrow */
 describe('blocks', function() {
-  it("array", function() {
-    var string   = "{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!";
-    var hash     = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
-    shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!",
-                    "Arrays iterate over the contents when not empty");
-
-    shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
-                    "Arrays ignore the contents when empty");
+  it('array', function() {
+    var string = '{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!';
+    var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
+    shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!',
+                    'Arrays iterate over the contents when not empty');
+
+    shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
+                    'Arrays ignore the contents when empty');
   });
 
   it('array without data', function() {
-    var string   = '{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}';
-    var hash     = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
-    shouldCompileTo(string, [hash,,,,false], 'goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE');
+    var string = '{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}';
+    var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
+    shouldCompileTo(string, [hash,,, false], 'goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE');
   });
 
-  it("array with @index", function() {
-    var string = "{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!";
-    var hash   = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
+  it('array with @index', function() {
+    var string = '{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!';
+    var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
 
     var template = CompilerContext.compile(string);
     var result = template(hash);
 
-    equal(result, "0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!", "The @index variable is used");
+    equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used');
   });
-  
-  it("empty block", function() {
-    var string   = "{{#goodbyes}}{{/goodbyes}}cruel {{world}}!";
-    var hash     = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
-    shouldCompileTo(string, hash, "cruel world!",
-                    "Arrays iterate over the contents when not empty");
-
-    shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
-                    "Arrays ignore the contents when empty");
+
+  it('empty block', function() {
+    var string = '{{#goodbyes}}{{/goodbyes}}cruel {{world}}!';
+    var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
+    shouldCompileTo(string, hash, 'cruel world!',
+                    'Arrays iterate over the contents when not empty');
+
+    shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
+                    'Arrays ignore the contents when empty');
   });
 
-  it("block with complex lookup", function() {
-    var string = "{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}";
-    var hash     = {name: "Alan", goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}]};
+  it('block with complex lookup', function() {
+    var string = '{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}';
+    var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]};
 
-    shouldCompileTo(string, hash, "goodbye cruel Alan! Goodbye cruel Alan! GOODBYE cruel Alan! ",
-                    "Templates can access variables in contexts up the stack with relative path syntax");
+    shouldCompileTo(string, hash, 'goodbye cruel Alan! Goodbye cruel Alan! GOODBYE cruel Alan! ',
+                    'Templates can access variables in contexts up the stack with relative path syntax');
   });
 
   it('multiple blocks with complex lookup', function() {
     var string = '{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}';
-    var hash     = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]};
+    var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]};
 
     shouldCompileTo(string, hash, 'AlanAlanAlanAlanAlanAlan');
   });
 
-  it("block with complex lookup using nested context", function() {
-    var string = "{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}";
+  it('block with complex lookup using nested context', function() {
+    var string = '{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}';
 
     shouldThrow(function() {
       CompilerContext.compile(string);
     }, Error);
   });
 
-  it("block with deep nested complex lookup", function() {
-    var string = "{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}";
-    var hash = {omg: "OMG!", outer: [{ sibling: 'sad', inner: [{ text: "goodbye" }] }] };
+  it('block with deep nested complex lookup', function() {
+    var string = '{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}';
+    var hash = {omg: 'OMG!', outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }] };
 
-    shouldCompileTo(string, hash, "Goodbye cruel sad OMG!");
+    shouldCompileTo(string, hash, 'Goodbye cruel sad OMG!');
   });
 
   describe('inverted sections', function() {
-    it("inverted sections with unset value", function() {
-      var string = "{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}";
+    it('inverted sections with unset value', function() {
+      var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
       var hash = {};
-      shouldCompileTo(string, hash, "Right On!", "Inverted section rendered when value isn't set.");
+      shouldCompileTo(string, hash, 'Right On!', "Inverted section rendered when value isn't set.");
     });
 
-    it("inverted section with false value", function() {
-      var string = "{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}";
+    it('inverted section with false value', function() {
+      var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
       var hash = {goodbyes: false};
-      shouldCompileTo(string, hash, "Right On!", "Inverted section rendered when value is false.");
+      shouldCompileTo(string, hash, 'Right On!', 'Inverted section rendered when value is false.');
     });
 
-    it("inverted section with empty set", function() {
-      var string = "{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}";
+    it('inverted section with empty set', function() {
+      var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
       var hash = {goodbyes: []};
-      shouldCompileTo(string, hash, "Right On!", "Inverted section rendered when value is empty set.");
+      shouldCompileTo(string, hash, 'Right On!', 'Inverted section rendered when value is empty set.');
     });
 
-    it("block inverted sections", function() {
-      shouldCompileTo("{{#people}}{{name}}{{^}}{{none}}{{/people}}", {none: "No people"},
-        "No people");
+    it('block inverted sections', function() {
+      shouldCompileTo('{{#people}}{{name}}{{^}}{{none}}{{/people}}', {none: 'No people'},
+        'No people');
     });
-    it("chained inverted sections", function() {
-      shouldCompileTo("{{#people}}{{name}}{{else if none}}{{none}}{{/people}}", {none: "No people"},
-        "No people");
-      shouldCompileTo("{{#people}}{{name}}{{else if nothere}}fail{{else unless nothere}}{{none}}{{/people}}", {none: "No people"},
-        "No people");
-      shouldCompileTo("{{#people}}{{name}}{{else if none}}{{none}}{{else}}fail{{/people}}", {none: "No people"},
-        "No people");
+    it('chained inverted sections', function() {
+      shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{/people}}', {none: 'No people'},
+        'No people');
+      shouldCompileTo('{{#people}}{{name}}{{else if nothere}}fail{{else unless nothere}}{{none}}{{/people}}', {none: 'No people'},
+        'No people');
+      shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{else}}fail{{/people}}', {none: 'No people'},
+        'No people');
     });
-    it("chained inverted sections with mismatch", function() {
+    it('chained inverted sections with mismatch', function() {
       shouldThrow(function() {
-        shouldCompileTo("{{#people}}{{name}}{{else if none}}{{none}}{{/if}}", {none: "No people"},
-          "No people");
+        shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{/if}}', {none: 'No people'},
+          'No people');
       }, Error);
     });
 
-    it("block inverted sections with empty arrays", function() {
-      shouldCompileTo("{{#people}}{{name}}{{^}}{{none}}{{/people}}", {none: "No people", people: []},
-        "No people");
+    it('block inverted sections with empty arrays', function() {
+      shouldCompileTo('{{#people}}{{name}}{{^}}{{none}}{{/people}}', {none: 'No people', people: []},
+        'No people');
     });
   });
 
@@ -131,23 +130,23 @@ describe('blocks', function() {
   });
 
   describe('compat mode', function() {
-    it("block with deep recursive lookup lookup", function() {
-      var string = "{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}";
-      var hash = {omg: "OMG!", outer: [{ inner: [{ text: "goodbye" }] }] };
+    it('block with deep recursive lookup lookup', function() {
+      var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}';
+      var hash = {omg: 'OMG!', outer: [{ inner: [{ text: 'goodbye' }] }] };
 
-      shouldCompileTo(string, [hash, undefined, undefined, true], "Goodbye cruel OMG!");
+      shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel OMG!');
     });
-    it("block with deep recursive pathed lookup", function() {
-      var string = "{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}";
-      var hash = {omg: {yes: "OMG!"}, outer: [{ inner: [{ yes: 'no', text: "goodbye" }] }] };
+    it('block with deep recursive pathed lookup', function() {
+      var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
+      var hash = {omg: {yes: 'OMG!'}, outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] };
 
-      shouldCompileTo(string, [hash, undefined, undefined, true], "Goodbye cruel OMG!");
+      shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel OMG!');
     });
-    it("block with missed recursive lookup", function() {
-      var string = "{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}";
-      var hash = {omg: {no: "OMG!"}, outer: [{ inner: [{ yes: 'no', text: "goodbye" }] }] };
+    it('block with missed recursive lookup', function() {
+      var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
+      var hash = {omg: {no: 'OMG!'}, outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] };
 
-      shouldCompileTo(string, [hash, undefined, undefined, true], "Goodbye cruel ");
+      shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel ');
     });
   });
 });
diff --git a/spec/builtins.js b/spec/builtins.js
index f3b4baaba..46d70baac 100644
--- a/spec/builtins.js
+++ b/spec/builtins.js
@@ -1,52 +1,51 @@
-/*global CompilerContext, shouldCompileTo, shouldThrow, compileWithPartials, handlebarsEnv */
 describe('builtin helpers', function() {
   describe('#if', function() {
-    it("if", function() {
-      var string   = "{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!";
-      shouldCompileTo(string, {goodbye: true, world: "world"}, "GOODBYE cruel world!",
-                      "if with boolean argument shows the contents when true");
-      shouldCompileTo(string, {goodbye: "dummy", world: "world"}, "GOODBYE cruel world!",
-                      "if with string argument shows the contents");
-      shouldCompileTo(string, {goodbye: false, world: "world"}, "cruel world!",
-                      "if with boolean argument does not show the contents when false");
-      shouldCompileTo(string, {world: "world"}, "cruel world!",
-                      "if with undefined does not show the contents");
-      shouldCompileTo(string, {goodbye: ['foo'], world: "world"}, "GOODBYE cruel world!",
-                      "if with non-empty array shows the contents");
-      shouldCompileTo(string, {goodbye: [], world: "world"}, "cruel world!",
-                      "if with empty array does not show the contents");
-      shouldCompileTo(string, {goodbye: 0, world: "world"}, "cruel world!",
-                      "if with zero does not show the contents");
-      shouldCompileTo("{{#if goodbye includeZero=true}}GOODBYE {{/if}}cruel {{world}}!",
-                      {goodbye: 0, world: "world"}, "GOODBYE cruel world!",
-                      "if with zero does not show the contents");
-    });
-
-    it("if with function argument", function() {
-      var string   = "{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!";
-      shouldCompileTo(string, {goodbye: function() {return true;}, world: "world"}, "GOODBYE cruel world!",
-                      "if with function shows the contents when function returns true");
-      shouldCompileTo(string, {goodbye: function() {return this.world;}, world: "world"}, "GOODBYE cruel world!",
-                      "if with function shows the contents when function returns string");
-      shouldCompileTo(string, {goodbye: function() {return false;}, world: "world"}, "cruel world!",
-                      "if with function does not show the contents when returns false");
-      shouldCompileTo(string, {goodbye: function() {return this.foo;}, world: "world"}, "cruel world!",
-                      "if with function does not show the contents when returns undefined");
+    it('if', function() {
+      var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!';
+      shouldCompileTo(string, {goodbye: true, world: 'world'}, 'GOODBYE cruel world!',
+                      'if with boolean argument shows the contents when true');
+      shouldCompileTo(string, {goodbye: 'dummy', world: 'world'}, 'GOODBYE cruel world!',
+                      'if with string argument shows the contents');
+      shouldCompileTo(string, {goodbye: false, world: 'world'}, 'cruel world!',
+                      'if with boolean argument does not show the contents when false');
+      shouldCompileTo(string, {world: 'world'}, 'cruel world!',
+                      'if with undefined does not show the contents');
+      shouldCompileTo(string, {goodbye: ['foo'], world: 'world'}, 'GOODBYE cruel world!',
+                      'if with non-empty array shows the contents');
+      shouldCompileTo(string, {goodbye: [], world: 'world'}, 'cruel world!',
+                      'if with empty array does not show the contents');
+      shouldCompileTo(string, {goodbye: 0, world: 'world'}, 'cruel world!',
+                      'if with zero does not show the contents');
+      shouldCompileTo('{{#if goodbye includeZero=true}}GOODBYE {{/if}}cruel {{world}}!',
+                      {goodbye: 0, world: 'world'}, 'GOODBYE cruel world!',
+                      'if with zero does not show the contents');
+    });
+
+    it('if with function argument', function() {
+      var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!';
+      shouldCompileTo(string, {goodbye: function() {return true; }, world: 'world'}, 'GOODBYE cruel world!',
+                      'if with function shows the contents when function returns true');
+      shouldCompileTo(string, {goodbye: function() {return this.world; }, world: 'world'}, 'GOODBYE cruel world!',
+                      'if with function shows the contents when function returns string');
+      shouldCompileTo(string, {goodbye: function() {return false; }, world: 'world'}, 'cruel world!',
+                      'if with function does not show the contents when returns false');
+      shouldCompileTo(string, {goodbye: function() {return this.foo; }, world: 'world'}, 'cruel world!',
+                      'if with function does not show the contents when returns undefined');
     });
   });
 
   describe('#with', function() {
-    it("with", function() {
-      var string = "{{#with person}}{{first}} {{last}}{{/with}}";
-      shouldCompileTo(string, {person: {first: "Alan", last: "Johnson"}}, "Alan Johnson");
+    it('with', function() {
+      var string = '{{#with person}}{{first}} {{last}}{{/with}}';
+      shouldCompileTo(string, {person: {first: 'Alan', last: 'Johnson'}}, 'Alan Johnson');
     });
-    it("with with function argument", function() {
-      var string = "{{#with person}}{{first}} {{last}}{{/with}}";
-      shouldCompileTo(string, {person: function() { return {first: "Alan", last: "Johnson"};}}, "Alan Johnson");
+    it('with with function argument', function() {
+      var string = '{{#with person}}{{first}} {{last}}{{/with}}';
+      shouldCompileTo(string, {person: function() { return {first: 'Alan', last: 'Johnson'}; }}, 'Alan Johnson');
     });
-    it("with with else", function() {
-      var string = "{{#with person}}Person is present{{else}}Person is not present{{/with}}";
-      shouldCompileTo(string, {}, "Person is not present");
+    it('with with else', function() {
+      var string = '{{#with person}}Person is present{{else}}Person is not present{{/with}}';
+      shouldCompileTo(string, {}, 'Person is not present');
     });
   });
 
@@ -57,73 +56,73 @@ describe('builtin helpers', function() {
       });
     });
 
-    it("each", function() {
-      var string   = "{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!";
-      var hash     = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
-      shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!",
-                      "each with array argument iterates over the contents when not empty");
-      shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
-                      "each with array argument ignores the contents when empty");
+    it('each', function() {
+      var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
+      var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
+      shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!',
+                      'each with array argument iterates over the contents when not empty');
+      shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
+                      'each with array argument ignores the contents when empty');
     });
 
     it('each without data', function() {
-      var string   = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
-      var hash     = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
-      shouldCompileTo(string, [hash,,,,false], 'goodbye! Goodbye! GOODBYE! cruel world!');
+      var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
+      var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
+      shouldCompileTo(string, [hash,,,, false], 'goodbye! Goodbye! GOODBYE! cruel world!');
 
       hash = {goodbyes: 'cruel', world: 'world'};
-      shouldCompileTo('{{#each .}}{{.}}{{/each}}', [hash,,,,false], 'cruelworld');
+      shouldCompileTo('{{#each .}}{{.}}{{/each}}', [hash,,,, false], 'cruelworld');
     });
 
     it('each without context', function() {
-      var string   = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
-      shouldCompileTo(string, [,,,,], 'cruel !');
+      var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
+      shouldCompileTo(string, [,,,, ], 'cruel !');
     });
 
-    it("each with an object and @key", function() {
-      var string   = "{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!";
+    it('each with an object and @key', function() {
+      var string = '{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!';
 
       function Clazz() {
         this['<b>#1</b>'] = {text: 'goodbye'};
         this[2] = {text: 'GOODBYE'};
       }
       Clazz.prototype.foo = 'fail';
-      var hash     = {goodbyes: new Clazz(), world: 'world'};
+      var hash = {goodbyes: new Clazz(), world: 'world'};
 
       // Object property iteration order is undefined according to ECMA spec,
       // so we need to check both possible orders
       // @see http://stackoverflow.com/questions/280713/elements-order-in-a-for-in-loop
       var actual = compileWithPartials(string, hash);
-      var expected1 = "&lt;b&gt;#1&lt;/b&gt;. goodbye! 2. GOODBYE! cruel world!";
-      var expected2 = "2. GOODBYE! &lt;b&gt;#1&lt;/b&gt;. goodbye! cruel world!";
+      var expected1 = '&lt;b&gt;#1&lt;/b&gt;. goodbye! 2. GOODBYE! cruel world!';
+      var expected2 = '2. GOODBYE! &lt;b&gt;#1&lt;/b&gt;. goodbye! cruel world!';
 
-      equals(actual === expected1 || actual === expected2, true, "each with object argument iterates over the contents when not empty");
+      equals(actual === expected1 || actual === expected2, true, 'each with object argument iterates over the contents when not empty');
       shouldCompileTo(string, {goodbyes: {}, world: 'world'}, 'cruel world!');
     });
 
-    it("each with @index", function() {
-      var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!";
-      var hash   = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
+    it('each with @index', function() {
+      var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!';
+      var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
 
-      equal(result, "0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!", "The @index variable is used");
+      equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used');
     });
 
-    it("each with nested @index", function() {
-      var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}cruel {{world}}!";
-      var hash   = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
+    it('each with nested @index', function() {
+      var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}cruel {{world}}!';
+      var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
 
-      equal(result, "0. goodbye! 0 1 2 After 0 1. Goodbye! 0 1 2 After 1 2. GOODBYE! 0 1 2 After 2 cruel world!", "The @index variable is used");
+      equal(result, '0. goodbye! 0 1 2 After 0 1. Goodbye! 0 1 2 After 1 2. GOODBYE! 0 1 2 After 2 cruel world!', 'The @index variable is used');
     });
 
     it('each with block params', function() {
       var string = '{{#each goodbyes as |value index|}}{{index}}. {{value.text}}! {{#each ../goodbyes as |childValue childIndex|}} {{index}} {{childIndex}}{{/each}} After {{index}} {{/each}}{{index}}cruel {{world}}!';
-      var hash   = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}], world: 'world'};
+      var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}], world: 'world'};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
@@ -131,88 +130,88 @@ describe('builtin helpers', function() {
       equal(result, '0. goodbye!  0 0 0 1 After 0 1. Goodbye!  1 0 1 1 After 1 cruel world!');
     });
 
-    it("each object with @index", function() {
-      var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!";
-      var hash   = {goodbyes: {'a': {text: "goodbye"}, b: {text: "Goodbye"}, c: {text: "GOODBYE"}}, world: "world"};
+    it('each object with @index', function() {
+      var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!';
+      var hash = {goodbyes: {'a': {text: 'goodbye'}, b: {text: 'Goodbye'}, c: {text: 'GOODBYE'}}, world: 'world'};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
 
-      equal(result, "0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!", "The @index variable is used");
+      equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used');
     });
 
 
-    it("each with @first", function() {
-      var string = "{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!";
-      var hash   = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
+    it('each with @first', function() {
+      var string = '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
+      var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
 
-      equal(result, "goodbye! cruel world!", "The @first variable is used");
+      equal(result, 'goodbye! cruel world!', 'The @first variable is used');
     });
 
-    it("each with nested @first", function() {
-      var string = "{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!";
-      var hash   = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
+    it('each with nested @first', function() {
+      var string = '{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!';
+      var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
 
-      equal(result, "(goodbye! goodbye! goodbye!) (goodbye!) (goodbye!) cruel world!", "The @first variable is used");
+      equal(result, '(goodbye! goodbye! goodbye!) (goodbye!) (goodbye!) cruel world!', 'The @first variable is used');
     });
 
-    it("each object with @first", function() {
-      var string = "{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!";
-      var hash   = {goodbyes: {'foo': {text: "goodbye"}, bar: {text: "Goodbye"}}, world: "world"};
+    it('each object with @first', function() {
+      var string = '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
+      var hash = {goodbyes: {'foo': {text: 'goodbye'}, bar: {text: 'Goodbye'}}, world: 'world'};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
 
-      equal(result, "goodbye! cruel world!", "The @first variable is used");
+      equal(result, 'goodbye! cruel world!', 'The @first variable is used');
     });
 
-    it("each with @last", function() {
-      var string = "{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!";
-      var hash   = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
+    it('each with @last', function() {
+      var string = '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
+      var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
 
-      equal(result, "GOODBYE! cruel world!", "The @last variable is used");
+      equal(result, 'GOODBYE! cruel world!', 'The @last variable is used');
     });
 
-    it("each object with @last", function() {
-      var string = "{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!";
-      var hash   = {goodbyes: {'foo': {text: "goodbye"}, bar: {text: "Goodbye"}}, world: "world"};
+    it('each object with @last', function() {
+      var string = '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!';
+      var hash = {goodbyes: {'foo': {text: 'goodbye'}, bar: {text: 'Goodbye'}}, world: 'world'};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
 
-      equal(result, "Goodbye! cruel world!", "The @last variable is used");
+      equal(result, 'Goodbye! cruel world!', 'The @last variable is used');
     });
 
-    it("each with nested @last", function() {
-      var string = "{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!";
-      var hash   = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
+    it('each with nested @last', function() {
+      var string = '{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!';
+      var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
 
-      equal(result, "(GOODBYE!) (GOODBYE!) (GOODBYE! GOODBYE! GOODBYE!) cruel world!", "The @last variable is used");
+      equal(result, '(GOODBYE!) (GOODBYE!) (GOODBYE! GOODBYE! GOODBYE!) cruel world!', 'The @last variable is used');
     });
 
-    it("each with function argument", function() {
-      var string = "{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!";
-      var hash   = {goodbyes: function () { return [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}];}, world: "world"};
-      shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!",
-                "each with array function argument iterates over the contents when not empty");
-      shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
-                "each with array function argument ignores the contents when empty");
+    it('each with function argument', function() {
+      var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!';
+      var hash = {goodbyes: function() { return [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]; }, world: 'world'};
+      shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!',
+                'each with array function argument iterates over the contents when not empty');
+      shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
+                'each with array function argument ignores the contents when empty');
     });
 
-    it("data passed to helpers", function() {
-      var string = "{{#each letters}}{{this}}{{detectDataInsideEach}}{{/each}}";
+    it('data passed to helpers', function() {
+      var string = '{{#each letters}}{{this}}{{detectDataInsideEach}}{{/each}}';
       var hash = {letters: ['a', 'b', 'c']};
 
       var template = CompilerContext.compile(string);
@@ -224,106 +223,108 @@ describe('builtin helpers', function() {
       equal(result, 'a!b!c!', 'should output data');
     });
 
-    it("each on implicit context", function() {
+    it('each on implicit context', function() {
       shouldThrow(function() {
-        var template = CompilerContext.compile("{{#each}}{{text}}! {{/each}}cruel world!");
+        var template = CompilerContext.compile('{{#each}}{{text}}! {{/each}}cruel world!');
         template({});
       }, handlebarsEnv.Exception, 'Must pass iterator to #each');
     });
   });
 
-  describe("#log", function() {
+  describe('#log', function() {
+    /*eslint-disable no-console */
     if (typeof console === 'undefined') {
       return;
     }
 
-    var log,
-        info,
-        error;
+    var $log,
+        $info,
+        $error;
     beforeEach(function() {
-      log = console.log;
-      info = console.info;
-      error = console.error;
+      $log = console.log;
+      $info = console.info;
+      $error = console.error;
     });
     afterEach(function() {
-      console.log = log;
-      console.info = info;
-      console.error = error;
+      console.log = $log;
+      console.info = $info;
+      console.error = $error;
     });
 
     it('should call logger at default level', function() {
-      var string = "{{log blah}}";
-      var hash   = { blah: "whee" };
+      var string = '{{log blah}}';
+      var hash = { blah: 'whee' };
 
       var levelArg, logArg;
-      handlebarsEnv.log = function(level, arg){
+      handlebarsEnv.log = function(level, arg) {
         levelArg = level;
         logArg = arg;
       };
 
-      shouldCompileTo(string, hash, "", "log should not display");
-      equals(1, levelArg, "should call log with 1");
-      equals("whee", logArg, "should call log with 'whee'");
+      shouldCompileTo(string, hash, '', 'log should not display');
+      equals(1, levelArg, 'should call log with 1');
+      equals('whee', logArg, "should call log with 'whee'");
     });
     it('should call logger at data level', function() {
-      var string = "{{log blah}}";
-      var hash   = { blah: "whee" };
+      var string = '{{log blah}}';
+      var hash = { blah: 'whee' };
 
       var levelArg, logArg;
-      handlebarsEnv.log = function(level, arg){
+      handlebarsEnv.log = function(level, arg) {
         levelArg = level;
         logArg = arg;
       };
 
-      shouldCompileTo(string, [hash,,,,{level: '03'}], "");
+      shouldCompileTo(string, [hash,,,, {level: '03'}], '');
       equals(3, levelArg);
-      equals("whee", logArg);
+      equals('whee', logArg);
     });
     it('should output to info', function() {
-      var string = "{{log blah}}";
-      var hash   = { blah: "whee" };
+      var string = '{{log blah}}';
+      var hash = { blah: 'whee' };
       var called;
 
-      console.info = function(log) {
-        equals("whee", log);
+      console.info = function(info) {
+        equals('whee', info);
         called = true;
       };
       console.log = function(log) {
-        equals("whee", log);
+        equals('whee', log);
         called = true;
       };
 
-      shouldCompileTo(string, hash, "");
+      shouldCompileTo(string, hash, '');
       equals(true, called);
     });
     it('should log at data level', function() {
-      var string = "{{log blah}}";
-      var hash   = { blah: "whee" };
+      var string = '{{log blah}}';
+      var hash = { blah: 'whee' };
       var called;
 
       console.error = function(log) {
-        equals("whee", log);
+        equals('whee', log);
         called = true;
       };
 
-      shouldCompileTo(string, [hash,,,,{level: '03'}], "");
+      shouldCompileTo(string, [hash,,,, {level: '03'}], '');
       equals(true, called);
     });
     it('should handle missing logger', function() {
-      var string = "{{log blah}}";
-      var hash   = { blah: "whee" };
+      var string = '{{log blah}}';
+      var hash = { blah: 'whee' };
 
       console.error = undefined;
 
-      shouldCompileTo(string, [hash,,,,{level: '03'}], "");
+      shouldCompileTo(string, [hash,,,, {level: '03'}], '');
     });
+    /*eslint-enable no-console */
   });
 
 
   describe('#lookup', function() {
     it('should lookup arbitrary content', function() {
       var string = '{{#each goodbyes}}{{lookup ../data .}}{{/each}}',
-          hash   = {goodbyes: [0, 1], data: ['foo', 'bar']};
+          hash = {goodbyes: [0, 1], data: ['foo', 'bar']};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
@@ -332,7 +333,7 @@ describe('builtin helpers', function() {
     });
     it('should not fail on undefined value', function() {
       var string = '{{#each goodbyes}}{{lookup ../bar .}}{{/each}}',
-          hash   = {goodbyes: [0, 1], data: ['foo', 'bar']};
+          hash = {goodbyes: [0, 1], data: ['foo', 'bar']};
 
       var template = CompilerContext.compile(string);
       var result = template(hash);
diff --git a/spec/compiler.js b/spec/compiler.js
index f9eba28fb..fe4b63a30 100644
--- a/spec/compiler.js
+++ b/spec/compiler.js
@@ -1,5 +1,3 @@
-/*global Handlebars, shouldThrow */
-
 describe('compiler', function() {
   if (!Handlebars.compile) {
     return;
@@ -41,10 +39,10 @@ describe('compiler', function() {
     });
 
     it('can utilize AST instance', function() {
-      equal(Handlebars.compile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement("Hello")], null, {}))(), 'Hello');
+      equal(Handlebars.compile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement('Hello')], null, {}))(), 'Hello');
     });
 
-    it("can pass through an empty string", function() {
+    it('can pass through an empty string', function() {
       equal(Handlebars.compile('')(), '');
     });
   });
@@ -60,10 +58,10 @@ describe('compiler', function() {
     });
 
     it('can utilize AST instance', function() {
-      equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement("Hello")]), null, {})), true);
+      equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement('Hello')]), null, {})), true);
     });
 
-    it("can pass through an empty string", function() {
+    it('can pass through an empty string', function() {
       equal(/return ""/.test(Handlebars.precompile('')), true);
     });
   });
diff --git a/spec/data.js b/spec/data.js
index 1678eea85..547a2664e 100644
--- a/spec/data.js
+++ b/spec/data.js
@@ -1,25 +1,24 @@
-/*global CompilerContext, Handlebars, handlebarsEnv, shouldThrow */
 describe('data', function() {
-  it("passing in data to a compiled function that expects data - works with helpers", function() {
-    var template = CompilerContext.compile("{{hello}}", {data: true});
+  it('passing in data to a compiled function that expects data - works with helpers', function() {
+    var template = CompilerContext.compile('{{hello}}', {data: true});
 
     var helpers = {
       hello: function(options) {
-        return options.data.adjective + " "  + this.noun;
+        return options.data.adjective + ' ' + this.noun;
       }
     };
 
-    var result = template({noun: "cat"}, {helpers: helpers, data: {adjective: "happy"}});
-    equals("happy cat", result, "Data output by helper");
+    var result = template({noun: 'cat'}, {helpers: helpers, data: {adjective: 'happy'}});
+    equals('happy cat', result, 'Data output by helper');
   });
 
-  it("data can be looked up via @foo", function() {
-    var template = CompilerContext.compile("{{@hello}}");
-    var result = template({}, { data: { hello: "hello" } });
-    equals("hello", result, "@foo retrieves template data");
+  it('data can be looked up via @foo', function() {
+    var template = CompilerContext.compile('{{@hello}}');
+    var result = template({}, { data: { hello: 'hello' } });
+    equals('hello', result, '@foo retrieves template data');
   });
 
-  it("deep @foo triggers automatic top-level data", function() {
+  it('deep @foo triggers automatic top-level data', function() {
     var template = CompilerContext.compile('{{#let world="world"}}{{#if foo}}{{#if foo}}Hello {{@world}}{{/if}}{{/if}}{{/let}}');
 
     var helpers = Handlebars.createFrame(handlebarsEnv.helpers);
@@ -28,65 +27,67 @@ describe('data', function() {
       var frame = Handlebars.createFrame(options.data);
 
       for (var prop in options.hash) {
-        frame[prop] = options.hash[prop];
+        if (prop in options.hash) {
+          frame[prop] = options.hash[prop];
+        }
       }
       return options.fn(this, { data: frame });
     };
 
     var result = template({ foo: true }, { helpers: helpers });
-    equals("Hello world", result, "Automatic data was triggered");
+    equals('Hello world', result, 'Automatic data was triggered');
   });
 
-  it("parameter data can be looked up via @foo", function() {
-    var template = CompilerContext.compile("{{hello @world}}");
+  it('parameter data can be looked up via @foo', function() {
+    var template = CompilerContext.compile('{{hello @world}}');
     var helpers = {
       hello: function(noun) {
-        return "Hello " + noun;
+        return 'Hello ' + noun;
       }
     };
 
-    var result = template({}, { helpers: helpers, data: { world: "world" } });
-    equals("Hello world", result, "@foo as a parameter retrieves template data");
+    var result = template({}, { helpers: helpers, data: { world: 'world' } });
+    equals('Hello world', result, '@foo as a parameter retrieves template data');
   });
 
-  it("hash values can be looked up via @foo", function() {
-    var template = CompilerContext.compile("{{hello noun=@world}}");
+  it('hash values can be looked up via @foo', function() {
+    var template = CompilerContext.compile('{{hello noun=@world}}');
     var helpers = {
       hello: function(options) {
-        return "Hello " + options.hash.noun;
+        return 'Hello ' + options.hash.noun;
       }
     };
 
-    var result = template({}, { helpers: helpers, data: { world: "world" } });
-    equals("Hello world", result, "@foo as a parameter retrieves template data");
+    var result = template({}, { helpers: helpers, data: { world: 'world' } });
+    equals('Hello world', result, '@foo as a parameter retrieves template data');
   });
 
-  it("nested parameter data can be looked up via @foo.bar", function() {
-    var template = CompilerContext.compile("{{hello @world.bar}}");
+  it('nested parameter data can be looked up via @foo.bar', function() {
+    var template = CompilerContext.compile('{{hello @world.bar}}');
     var helpers = {
       hello: function(noun) {
-        return "Hello " + noun;
+        return 'Hello ' + noun;
       }
     };
 
-    var result = template({}, { helpers: helpers, data: { world: {bar: "world" } } });
-    equals("Hello world", result, "@foo as a parameter retrieves template data");
+    var result = template({}, { helpers: helpers, data: { world: {bar: 'world' } } });
+    equals('Hello world', result, '@foo as a parameter retrieves template data');
   });
 
-  it("nested parameter data does not fail with @world.bar", function() {
-    var template = CompilerContext.compile("{{hello @world.bar}}");
+  it('nested parameter data does not fail with @world.bar', function() {
+    var template = CompilerContext.compile('{{hello @world.bar}}');
     var helpers = {
       hello: function(noun) {
-        return "Hello " + noun;
+        return 'Hello ' + noun;
       }
     };
 
-    var result = template({}, { helpers: helpers, data: { foo: {bar: "world" } } });
-    equals("Hello undefined", result, "@foo as a parameter retrieves template data");
+    var result = template({}, { helpers: helpers, data: { foo: {bar: 'world' } } });
+    equals('Hello undefined', result, '@foo as a parameter retrieves template data');
   });
 
-  it("parameter data throws when using complex scope references", function() {
-    var string = "{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}";
+  it('parameter data throws when using complex scope references', function() {
+    var string = '{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}';
 
     shouldThrow(function() {
       CompilerContext.compile(string);
@@ -104,131 +105,133 @@ describe('data', function() {
     equals('hello', result);
   });
 
-  it("data is inherited downstream", function() {
-    var template = CompilerContext.compile("{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}", { data: true });
+  it('data is inherited downstream', function() {
+    var template = CompilerContext.compile('{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}', { data: true });
     var helpers = {
       let: function(options) {
         var frame = Handlebars.createFrame(options.data);
         for (var prop in options.hash) {
-          frame[prop] = options.hash[prop];
+          if (prop in options.hash) {
+            frame[prop] = options.hash[prop];
+          }
         }
         return options.fn(this, {data: frame});
       }
     };
 
-    var result = template({ bar: { baz: "hello world" } }, { helpers: helpers, data: {} });
-    equals("2hello world1", result, "data variables are inherited downstream");
+    var result = template({ bar: { baz: 'hello world' } }, { helpers: helpers, data: {} });
+    equals('2hello world1', result, 'data variables are inherited downstream');
   });
 
-  it("passing in data to a compiled function that expects data - works with helpers in partials", function() {
-    var template = CompilerContext.compile("{{>my_partial}}", {data: true});
+  it('passing in data to a compiled function that expects data - works with helpers in partials', function() {
+    var template = CompilerContext.compile('{{>myPartial}}', {data: true});
 
     var partials = {
-      my_partial: CompilerContext.compile("{{hello}}", {data: true})
+      myPartial: CompilerContext.compile('{{hello}}', {data: true})
     };
 
     var helpers = {
       hello: function(options) {
-        return options.data.adjective + " "  + this.noun;
+        return options.data.adjective + ' ' + this.noun;
       }
     };
 
-    var result = template({noun: "cat"}, {helpers: helpers, partials: partials, data: {adjective: "happy"}});
-    equals("happy cat", result, "Data output by helper inside partial");
+    var result = template({noun: 'cat'}, {helpers: helpers, partials: partials, data: {adjective: 'happy'}});
+    equals('happy cat', result, 'Data output by helper inside partial');
   });
 
-  it("passing in data to a compiled function that expects data - works with helpers and parameters", function() {
-    var template = CompilerContext.compile("{{hello world}}", {data: true});
+  it('passing in data to a compiled function that expects data - works with helpers and parameters', function() {
+    var template = CompilerContext.compile('{{hello world}}', {data: true});
 
     var helpers = {
       hello: function(noun, options) {
-        return options.data.adjective + " "  + noun + (this.exclaim ? "!" : "");
+        return options.data.adjective + ' ' + noun + (this.exclaim ? '!' : '');
       }
     };
 
-    var result = template({exclaim: true, world: "world"}, {helpers: helpers, data: {adjective: "happy"}});
-    equals("happy world!", result, "Data output by helper");
+    var result = template({exclaim: true, world: 'world'}, {helpers: helpers, data: {adjective: 'happy'}});
+    equals('happy world!', result, 'Data output by helper');
   });
 
-  it("passing in data to a compiled function that expects data - works with block helpers", function() {
-    var template = CompilerContext.compile("{{#hello}}{{world}}{{/hello}}", {data: true});
+  it('passing in data to a compiled function that expects data - works with block helpers', function() {
+    var template = CompilerContext.compile('{{#hello}}{{world}}{{/hello}}', {data: true});
 
     var helpers = {
       hello: function(options) {
         return options.fn(this);
       },
       world: function(options) {
-        return options.data.adjective + " world" + (this.exclaim ? "!" : "");
+        return options.data.adjective + ' world' + (this.exclaim ? '!' : '');
       }
     };
 
-    var result = template({exclaim: true}, {helpers: helpers, data: {adjective: "happy"}});
-    equals("happy world!", result, "Data output by helper");
+    var result = template({exclaim: true}, {helpers: helpers, data: {adjective: 'happy'}});
+    equals('happy world!', result, 'Data output by helper');
   });
 
-  it("passing in data to a compiled function that expects data - works with block helpers that use ..", function() {
-    var template = CompilerContext.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true});
+  it('passing in data to a compiled function that expects data - works with block helpers that use ..', function() {
+    var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true});
 
     var helpers = {
       hello: function(options) {
-        return options.fn({exclaim: "?"});
+        return options.fn({exclaim: '?'});
       },
       world: function(thing, options) {
-        return options.data.adjective + " " + thing + (this.exclaim || "");
+        return options.data.adjective + ' ' + thing + (this.exclaim || '');
       }
     };
 
-    var result = template({exclaim: true, zomg: "world"}, {helpers: helpers, data: {adjective: "happy"}});
-    equals("happy world?", result, "Data output by helper");
+    var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy'}});
+    equals('happy world?', result, 'Data output by helper');
   });
 
-  it("passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..", function() {
-    var template = CompilerContext.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true});
+  it('passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..', function() {
+    var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true});
 
     var helpers = {
       hello: function(options) {
-        return options.data.accessData + " " + options.fn({exclaim: "?"});
+        return options.data.accessData + ' ' + options.fn({exclaim: '?'});
       },
       world: function(thing, options) {
-        return options.data.adjective + " " + thing + (this.exclaim || "");
+        return options.data.adjective + ' ' + thing + (this.exclaim || '');
       }
     };
 
-    var result = template({exclaim: true, zomg: "world"}, {helpers: helpers, data: {adjective: "happy", accessData: "#win"}});
-    equals("#win happy world?", result, "Data output by helper");
+    var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy', accessData: '#win'}});
+    equals('#win happy world?', result, 'Data output by helper');
   });
 
-  it("you can override inherited data when invoking a helper", function() {
-    var template = CompilerContext.compile("{{#hello}}{{world zomg}}{{/hello}}", {data: true});
+  it('you can override inherited data when invoking a helper', function() {
+    var template = CompilerContext.compile('{{#hello}}{{world zomg}}{{/hello}}', {data: true});
 
     var helpers = {
       hello: function(options) {
-        return options.fn({exclaim: "?", zomg: "world"}, { data: {adjective: "sad"} });
+        return options.fn({exclaim: '?', zomg: 'world'}, { data: {adjective: 'sad'} });
       },
       world: function(thing, options) {
-        return options.data.adjective + " " + thing + (this.exclaim || "");
+        return options.data.adjective + ' ' + thing + (this.exclaim || '');
       }
     };
 
-    var result = template({exclaim: true, zomg: "planet"}, {helpers: helpers, data: {adjective: "happy"}});
-    equals("sad world?", result, "Overriden data output by helper");
+    var result = template({exclaim: true, zomg: 'planet'}, {helpers: helpers, data: {adjective: 'happy'}});
+    equals('sad world?', result, 'Overriden data output by helper');
   });
 
 
-  it("you can override inherited data when invoking a helper with depth", function() {
-    var template = CompilerContext.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true});
+  it('you can override inherited data when invoking a helper with depth', function() {
+    var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true});
 
     var helpers = {
       hello: function(options) {
-        return options.fn({exclaim: "?"}, { data: {adjective: "sad"} });
+        return options.fn({exclaim: '?'}, { data: {adjective: 'sad'} });
       },
       world: function(thing, options) {
-        return options.data.adjective + " " + thing + (this.exclaim || "");
+        return options.data.adjective + ' ' + thing + (this.exclaim || '');
       }
     };
 
-    var result = template({exclaim: true, zomg: "world"}, {helpers: helpers, data: {adjective: "happy"}});
-    equals("sad world?", result, "Overriden data output by helper");
+    var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy'}});
+    equals('sad world?', result, 'Overriden data output by helper');
   });
 
   describe('@root', function() {
diff --git a/spec/env/browser.js b/spec/env/browser.js
index a9042e3fb..c9414d402 100644
--- a/spec/env/browser.js
+++ b/spec/env/browser.js
@@ -1,8 +1,6 @@
-/*global handlebarsEnv */
 require('./common');
 
-var _ = require('underscore'),
-    fs = require('fs'),
+var fs = require('fs'),
     vm = require('vm');
 
 global.Handlebars = 'no-conflict';
@@ -21,10 +19,12 @@ global.CompilerContext = {
 };
 
 function safeEval(templateSpec) {
+  /*eslint-disable no-eval, no-console */
   try {
     return eval('(' + templateSpec + ')');
   } catch (err) {
     console.error(templateSpec);
     throw err;
   }
+  /*eslint-enable no-eval, no-console */
 }
diff --git a/spec/env/common.js b/spec/env/common.js
index 9ffbc1462..e4c8ae537 100644
--- a/spec/env/common.js
+++ b/spec/env/common.js
@@ -1,4 +1,3 @@
-/*global CompilerContext, compileWithPartials, shouldCompileToWithPartials */
 global.shouldCompileTo = function(string, hashOrArray, expected, message) {
   shouldCompileToWithPartials(string, hashOrArray, false, expected, message);
 };
@@ -14,7 +13,7 @@ global.compileWithPartials = function(string, hashOrArray, partials) {
   var template,
       ary,
       options;
-  if(Object.prototype.toString.call(hashOrArray) === "[object Array]") {
+  if (Object.prototype.toString.call(hashOrArray) === '[object Array]') {
     ary = [];
     ary.push(hashOrArray[0]);
     ary.push({ helpers: hashOrArray[1], partials: hashOrArray[2] });
@@ -34,7 +33,7 @@ global.compileWithPartials = function(string, hashOrArray, partials) {
 
 global.equals = global.equal = function(a, b, msg) {
   if (a !== b) {
-    throw new Error("'" + a + "' should === '" + b + "'" + (msg ? ": " + msg : ''));
+    throw new Error("'" + a + "' should === '" + b + "'" + (msg ? ': ' + msg : ''));
   }
 };
 
diff --git a/spec/env/node.js b/spec/env/node.js
index d7db85346..62d9fe9b6 100644
--- a/spec/env/node.js
+++ b/spec/env/node.js
@@ -1,4 +1,3 @@
-/*global handlebarsEnv */
 require('./common');
 
 global.Handlebars = require('../../lib');
@@ -14,10 +13,12 @@ global.CompilerContext = {
 };
 
 function safeEval(templateSpec) {
+  /*eslint-disable no-eval, no-console */
   try {
     return eval('(' + templateSpec + ')');
   } catch (err) {
     console.error(templateSpec);
     throw err;
   }
+  /*eslint-enable no-eval, no-console */
 }
diff --git a/spec/env/runner.js b/spec/env/runner.js
index 143d30023..56fc8d443 100644
--- a/spec/env/runner.js
+++ b/spec/env/runner.js
@@ -1,3 +1,4 @@
+/*eslint-disable no-console */
 var fs = require('fs'),
     Mocha = require('mocha'),
     path = require('path');
@@ -6,7 +7,7 @@ var errors = 0,
     testDir = path.dirname(__dirname),
     grep = process.argv[2];
 
-var files = [ testDir + "/basic.js" ];
+var files = [ testDir + '/basic.js' ];
 
 var files = fs.readdirSync(testDir)
       .filter(function(name) { return (/.*\.js$/).test(name); })
@@ -15,7 +16,9 @@ var files = fs.readdirSync(testDir)
 run('./node', function() {
   run('./browser', function() {
     run('./runtime', function() {
+      /*eslint-disable no-process-exit */
       process.exit(errors);
+      /*eslint-enable no-process-exit */
     });
   });
 });
diff --git a/spec/env/runtime.js b/spec/env/runtime.js
index 0c144064e..a7b42f51e 100644
--- a/spec/env/runtime.js
+++ b/spec/env/runtime.js
@@ -1,8 +1,6 @@
-/*global handlebarsEnv */
 require('./common');
 
-var _ = require('underscore'),
-    fs = require('fs'),
+var fs = require('fs'),
     vm = require('vm');
 
 global.Handlebars = 'no-conflict';
@@ -10,15 +8,15 @@ vm.runInThisContext(fs.readFileSync(__dirname + '/../../dist/handlebars.runtime.
 
 var parse = require('../../dist/cjs/handlebars/compiler/base').parse;
 var compiler = require('../../dist/cjs/handlebars/compiler/compiler');
-var JavaScriptCompiler = require('../../dist/cjs/handlebars/compiler/javascript-compiler')['default'];
+var JavaScriptCompiler = require('../../dist/cjs/handlebars/compiler/javascript-compiler');
 
 global.CompilerContext = {
   browser: true,
 
   compile: function(template, options) {
     // Hack the compiler on to the environment for these specific tests
-    handlebarsEnv.precompile = function(template, options) {
-      return compiler.precompile(template, options, handlebarsEnv);
+    handlebarsEnv.precompile = function(precompileTemplate, precompileOptions) {
+      return compiler.precompile(precompileTemplate, precompileOptions, handlebarsEnv);
     };
     handlebarsEnv.parse = parse;
     handlebarsEnv.Compiler = compiler.Compiler;
@@ -29,8 +27,8 @@ global.CompilerContext = {
   },
   compileWithPartial: function(template, options) {
     // Hack the compiler on to the environment for these specific tests
-    handlebarsEnv.compile = function(template, options) {
-      return compiler.compile(template, options, handlebarsEnv);
+    handlebarsEnv.compile = function(compileTemplate, compileOptions) {
+      return compiler.compile(compileTemplate, compileOptions, handlebarsEnv);
     };
     handlebarsEnv.parse = parse;
     handlebarsEnv.Compiler = compiler.Compiler;
@@ -41,10 +39,12 @@ global.CompilerContext = {
 };
 
 function safeEval(templateSpec) {
+  /*eslint-disable no-eval, no-console */
   try {
     return eval('(' + templateSpec + ')');
   } catch (err) {
     console.error(templateSpec);
     throw err;
   }
+  /*eslint-enable no-eval, no-console */
 }
diff --git a/spec/helpers.js b/spec/helpers.js
index 712bb00a0..54ef0f288 100644
--- a/spec/helpers.js
+++ b/spec/helpers.js
@@ -1,165 +1,164 @@
-/*global CompilerContext, Handlebars, shouldCompileTo, shouldCompileToWithPartials, shouldThrow, handlebarsEnv */
 describe('helpers', function() {
-  it("helper with complex lookup$", function() {
-    var string = "{{#goodbyes}}{{{link ../prefix}}}{{/goodbyes}}";
-    var hash = {prefix: "/root", goodbyes: [{text: "Goodbye", url: "goodbye"}]};
+  it('helper with complex lookup$', function() {
+    var string = '{{#goodbyes}}{{{link ../prefix}}}{{/goodbyes}}';
+    var hash = {prefix: '/root', goodbyes: [{text: 'Goodbye', url: 'goodbye'}]};
     var helpers = {link: function(prefix) {
-      return "<a href='" + prefix + "/" + this.url + "'>" + this.text + "</a>";
+      return '<a href="' + prefix + '/' + this.url + '">' + this.text + '</a>';
     }};
-    shouldCompileTo(string, [hash, helpers], "<a href='/root/goodbye'>Goodbye</a>");
+    shouldCompileTo(string, [hash, helpers], '<a href="/root/goodbye">Goodbye</a>');
   });
 
-  it("helper for raw block gets raw content", function() {
-    var string   = "{{{{raw}}}} {{test}} {{{{/raw}}}}";
-    var hash = { test: "hello" };
+  it('helper for raw block gets raw content', function() {
+    var string = '{{{{raw}}}} {{test}} {{{{/raw}}}}';
+    var hash = { test: 'hello' };
     var helpers = { raw: function(options) {
         return options.fn();
     } };
-    shouldCompileTo(string, [hash, helpers], " {{test}} ",
-                    "raw block helper gets raw content");
+    shouldCompileTo(string, [hash, helpers], ' {{test}} ',
+                    'raw block helper gets raw content');
   });
-  
-  it("helper for raw block gets parameters", function() {
-    var string   = "{{{{raw 1 2 3}}}} {{test}} {{{{/raw}}}}";
-    var hash = { test: "hello" };
+
+  it('helper for raw block gets parameters', function() {
+    var string = '{{{{raw 1 2 3}}}} {{test}} {{{{/raw}}}}';
+    var hash = { test: 'hello' };
     var helpers = { raw: function(a, b, c, options) {
         return options.fn() + a + b + c;
     } };
-    shouldCompileTo(string, [hash, helpers], " {{test}} 123",
-                    "raw block helper gets raw content");
+    shouldCompileTo(string, [hash, helpers], ' {{test}} 123',
+                    'raw block helper gets raw content');
   });
-  
-  it("helper block with complex lookup expression", function() {
-    var string = "{{#goodbyes}}{{../name}}{{/goodbyes}}";
-    var hash = {name: "Alan"};
+
+  it('helper block with complex lookup expression', function() {
+    var string = '{{#goodbyes}}{{../name}}{{/goodbyes}}';
+    var hash = {name: 'Alan'};
     var helpers = {goodbyes: function(options) {
-      var out = "";
-      var byes = ["Goodbye", "goodbye", "GOODBYE"];
-      for (var i = 0,j = byes.length; i < j; i++) {
-        out += byes[i] + " " + options.fn(this) + "! ";
+      var out = '';
+      var byes = ['Goodbye', 'goodbye', 'GOODBYE'];
+      for (var i = 0, j = byes.length; i < j; i++) {
+        out += byes[i] + ' ' + options.fn(this) + '! ';
       }
       return out;
     }};
-    shouldCompileTo(string, [hash, helpers], "Goodbye Alan! goodbye Alan! GOODBYE Alan! ");
+    shouldCompileTo(string, [hash, helpers], 'Goodbye Alan! goodbye Alan! GOODBYE Alan! ');
   });
 
-  it("helper with complex lookup and nested template", function() {
-    var string = "{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}";
-    var hash = {prefix: '/root', goodbyes: [{text: "Goodbye", url: "goodbye"}]};
-    var helpers = {link: function (prefix, options) {
-        return "<a href='" + prefix + "/" + this.url + "'>" + options.fn(this) + "</a>";
+  it('helper with complex lookup and nested template', function() {
+    var string = '{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}';
+    var hash = {prefix: '/root', goodbyes: [{text: 'Goodbye', url: 'goodbye'}]};
+    var helpers = {link: function(prefix, options) {
+        return '<a href="' + prefix + '/' + this.url + '">' + options.fn(this) + '</a>';
     }};
-    shouldCompileToWithPartials(string, [hash, helpers], false, "<a href='/root/goodbye'>Goodbye</a>");
+    shouldCompileToWithPartials(string, [hash, helpers], false, '<a href="/root/goodbye">Goodbye</a>');
   });
 
-  it("helper with complex lookup and nested template in VM+Compiler", function() {
-    var string = "{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}";
-    var hash = {prefix: '/root', goodbyes: [{text: "Goodbye", url: "goodbye"}]};
-    var helpers = {link: function (prefix, options) {
-        return "<a href='" + prefix + "/" + this.url + "'>" + options.fn(this) + "</a>";
+  it('helper with complex lookup and nested template in VM+Compiler', function() {
+    var string = '{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}';
+    var hash = {prefix: '/root', goodbyes: [{text: 'Goodbye', url: 'goodbye'}]};
+    var helpers = {link: function(prefix, options) {
+        return '<a href="' + prefix + '/' + this.url + '">' + options.fn(this) + '</a>';
     }};
-    shouldCompileToWithPartials(string, [hash, helpers], true, "<a href='/root/goodbye'>Goodbye</a>");
+    shouldCompileToWithPartials(string, [hash, helpers], true, '<a href="/root/goodbye">Goodbye</a>');
   });
   it('helper returning undefined value', function() {
     shouldCompileTo(' {{nothere}}', [{}, {nothere: function() {}}], ' ');
     shouldCompileTo(' {{#nothere}}{{/nothere}}', [{}, {nothere: function() {}}], ' ');
   });
 
-  it("block helper", function() {
-    var string   = "{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!";
+  it('block helper', function() {
+    var string = '{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!';
     var template = CompilerContext.compile(string);
 
-    var result = template({world: "world"}, { helpers: {goodbyes: function(options) { return options.fn({text: "GOODBYE"}); }}});
-    equal(result, "GOODBYE! cruel world!", "Block helper executed");
+    var result = template({world: 'world'}, { helpers: {goodbyes: function(options) { return options.fn({text: 'GOODBYE'}); }}});
+    equal(result, 'GOODBYE! cruel world!', 'Block helper executed');
   });
 
-  it("block helper staying in the same context", function() {
-    var string   = "{{#form}}<p>{{name}}</p>{{/form}}";
+  it('block helper staying in the same context', function() {
+    var string = '{{#form}}<p>{{name}}</p>{{/form}}';
     var template = CompilerContext.compile(string);
 
-    var result = template({name: "Yehuda"}, {helpers: {form: function(options) { return "<form>" + options.fn(this) + "</form>"; } }});
-    equal(result, "<form><p>Yehuda</p></form>", "Block helper executed with current context");
+    var result = template({name: 'Yehuda'}, {helpers: {form: function(options) { return '<form>' + options.fn(this) + '</form>'; } }});
+    equal(result, '<form><p>Yehuda</p></form>', 'Block helper executed with current context');
   });
 
-  it("block helper should have context in this", function() {
-    var source = "<ul>{{#people}}<li>{{#link}}{{name}}{{/link}}</li>{{/people}}</ul>";
-    var link = function(options) {
+  it('block helper should have context in this', function() {
+    var source = '<ul>{{#people}}<li>{{#link}}{{name}}{{/link}}</li>{{/people}}</ul>';
+    function link(options) {
       return '<a href="/people/' + this.id + '">' + options.fn(this) + '</a>';
-    };
-    var data = { "people": [
-      { "name": "Alan", "id": 1 },
-      { "name": "Yehuda", "id": 2 }
+    }
+    var data = { 'people': [
+      { 'name': 'Alan', 'id': 1 },
+      { 'name': 'Yehuda', 'id': 2 }
     ]};
 
-    shouldCompileTo(source, [data, {link: link}], "<ul><li><a href=\"/people/1\">Alan</a></li><li><a href=\"/people/2\">Yehuda</a></li></ul>");
+    shouldCompileTo(source, [data, {link: link}], '<ul><li><a href=\"/people/1\">Alan</a></li><li><a href=\"/people/2\">Yehuda</a></li></ul>');
   });
 
-  it("block helper for undefined value", function() {
-    shouldCompileTo("{{#empty}}shouldn't render{{/empty}}", {}, "");
+  it('block helper for undefined value', function() {
+    shouldCompileTo("{{#empty}}shouldn't render{{/empty}}", {}, '');
   });
 
-  it("block helper passing a new context", function() {
-    var string   = "{{#form yehuda}}<p>{{name}}</p>{{/form}}";
+  it('block helper passing a new context', function() {
+    var string = '{{#form yehuda}}<p>{{name}}</p>{{/form}}';
     var template = CompilerContext.compile(string);
 
-    var result = template({yehuda: {name: "Yehuda"}}, { helpers: {form: function(context, options) { return "<form>" + options.fn(context) + "</form>"; }}});
-    equal(result, "<form><p>Yehuda</p></form>", "Context variable resolved");
+    var result = template({yehuda: {name: 'Yehuda'}}, { helpers: {form: function(context, options) { return '<form>' + options.fn(context) + '</form>'; }}});
+    equal(result, '<form><p>Yehuda</p></form>', 'Context variable resolved');
   });
 
-  it("block helper passing a complex path context", function() {
-    var string   = "{{#form yehuda/cat}}<p>{{name}}</p>{{/form}}";
+  it('block helper passing a complex path context', function() {
+    var string = '{{#form yehuda/cat}}<p>{{name}}</p>{{/form}}';
     var template = CompilerContext.compile(string);
 
-    var result = template({yehuda: {name: "Yehuda", cat: {name: "Harold"}}}, { helpers: {form: function(context, options) { return "<form>" + options.fn(context) + "</form>"; }}});
-    equal(result, "<form><p>Harold</p></form>", "Complex path variable resolved");
+    var result = template({yehuda: {name: 'Yehuda', cat: {name: 'Harold'}}}, { helpers: {form: function(context, options) { return '<form>' + options.fn(context) + '</form>'; }}});
+    equal(result, '<form><p>Harold</p></form>', 'Complex path variable resolved');
   });
 
-  it("nested block helpers", function() {
-    var string   = "{{#form yehuda}}<p>{{name}}</p>{{#link}}Hello{{/link}}{{/form}}";
+  it('nested block helpers', function() {
+    var string = '{{#form yehuda}}<p>{{name}}</p>{{#link}}Hello{{/link}}{{/form}}';
     var template = CompilerContext.compile(string);
 
     var result = template({
-      yehuda: {name: "Yehuda" }
+      yehuda: {name: 'Yehuda' }
     }, {
       helpers: {
-        link: function(options) { return "<a href='" + this.name + "'>" + options.fn(this) + "</a>"; },
-        form: function(context, options) { return "<form>" + options.fn(context) + "</form>"; }
+        link: function(options) { return '<a href="' + this.name + '">' + options.fn(this) + '</a>'; },
+        form: function(context, options) { return '<form>' + options.fn(context) + '</form>'; }
       }
     });
-    equal(result, "<form><p>Yehuda</p><a href='Yehuda'>Hello</a></form>", "Both blocks executed");
+    equal(result, '<form><p>Yehuda</p><a href="Yehuda">Hello</a></form>', 'Both blocks executed');
   });
 
-  it("block helper inverted sections", function() {
-    var string = "{{#list people}}{{name}}{{^}}<em>Nobody's here</em>{{/list}}";
-    var list = function(context, options) {
+  it('block helper inverted sections', function() {
+    var string = '{{#list people}}{{name}}{{^}}<em>Nobody\'s here</em>{{/list}}';
+    function list(context, options) {
       if (context.length > 0) {
-        var out = "<ul>";
-        for(var i = 0,j=context.length; i < j; i++) {
-          out += "<li>";
+        var out = '<ul>';
+        for (var i = 0, j = context.length; i < j; i++) {
+          out += '<li>';
           out += options.fn(context[i]);
-          out += "</li>";
+          out += '</li>';
         }
-        out += "</ul>";
+        out += '</ul>';
         return out;
       } else {
-        return "<p>" + options.inverse(this) + "</p>";
+        return '<p>' + options.inverse(this) + '</p>';
       }
-    };
+    }
 
-    var hash = {people: [{name: "Alan"}, {name: "Yehuda"}]};
+    var hash = {people: [{name: 'Alan'}, {name: 'Yehuda'}]};
     var empty = {people: []};
     var rootMessage = {
       people: [],
-      message: "Nobody's here"
+      message: 'Nobody\'s here'
     };
 
-    var messageString = "{{#list people}}Hello{{^}}{{message}}{{/list}}";
+    var messageString = '{{#list people}}Hello{{^}}{{message}}{{/list}}';
 
     // the meaning here may be kind of hard to catch, but list.not is always called,
     // so we should see the output of both
-    shouldCompileTo(string, [hash, { list: list }], "<ul><li>Alan</li><li>Yehuda</li></ul>", "an inverse wrapper is passed in as a new context");
-    shouldCompileTo(string, [empty, { list: list }], "<p><em>Nobody's here</em></p>", "an inverse wrapper can be optionally called");
-    shouldCompileTo(messageString, [rootMessage, { list: list }], "<p>Nobody&#x27;s here</p>", "the context of an inverse is the parent of the block");
+    shouldCompileTo(string, [hash, { list: list }], '<ul><li>Alan</li><li>Yehuda</li></ul>', 'an inverse wrapper is passed in as a new context');
+    shouldCompileTo(string, [empty, { list: list }], '<p><em>Nobody\'s here</em></p>', 'an inverse wrapper can be optionally called');
+    shouldCompileTo(messageString, [rootMessage, { list: list }], '<p>Nobody&#x27;s here</p>', 'the context of an inverse is the parent of the block');
   });
 
   it('pathed lambas with parameters', function() {
@@ -178,43 +177,47 @@ describe('helpers', function() {
     shouldCompileTo('{{hash/helper 1}}', [hash, helpers], 'winning');
   });
 
-  describe("helpers hash", function() {
-    it("providing a helpers hash", function() {
-      shouldCompileTo("Goodbye {{cruel}} {{world}}!", [{cruel: "cruel"}, {world: function() { return "world"; }}], "Goodbye cruel world!",
-                      "helpers hash is available");
+  describe('helpers hash', function() {
+    it('providing a helpers hash', function() {
+      shouldCompileTo('Goodbye {{cruel}} {{world}}!', [{cruel: 'cruel'}, {world: function() { return 'world'; }}], 'Goodbye cruel world!',
+                      'helpers hash is available');
 
-      shouldCompileTo("Goodbye {{#iter}}{{cruel}} {{world}}{{/iter}}!", [{iter: [{cruel: "cruel"}]}, {world: function() { return "world"; }}],
-                      "Goodbye cruel world!", "helpers hash is available inside other blocks");
+      shouldCompileTo('Goodbye {{#iter}}{{cruel}} {{world}}{{/iter}}!', [{iter: [{cruel: 'cruel'}]}, {world: function() { return 'world'; }}],
+                      'Goodbye cruel world!', 'helpers hash is available inside other blocks');
     });
 
-    it("in cases of conflict, helpers win", function() {
-      shouldCompileTo("{{{lookup}}}", [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], "helpers",
-                      "helpers hash has precedence escaped expansion");
-      shouldCompileTo("{{lookup}}", [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], "helpers",
-                      "helpers hash has precedence simple expansion");
+    it('in cases of conflict, helpers win', function() {
+      shouldCompileTo('{{{lookup}}}', [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], 'helpers',
+                      'helpers hash has precedence escaped expansion');
+      shouldCompileTo('{{lookup}}', [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], 'helpers',
+                      'helpers hash has precedence simple expansion');
     });
 
-    it("the helpers hash is available is nested contexts", function() {
-      shouldCompileTo("{{#outer}}{{#inner}}{{helper}}{{/inner}}{{/outer}}",
-                    [{'outer': {'inner': {'unused':[]}}},  {'helper': function() { return 'helper'; }}], "helper",
-                    "helpers hash is available in nested contexts.");
+    it('the helpers hash is available is nested contexts', function() {
+      shouldCompileTo(
+        '{{#outer}}{{#inner}}{{helper}}{{/inner}}{{/outer}}',
+        [
+          {'outer': {'inner': {'unused': []}}},
+          {'helper': function() { return 'helper'; }}
+        ],
+        'helper',
+        'helpers hash is available in nested contexts.');
     });
 
-    it("the helper hash should augment the global hash", function() {
+    it('the helper hash should augment the global hash', function() {
       handlebarsEnv.registerHelper('test_helper', function() { return 'found it!'; });
 
       shouldCompileTo(
-        "{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}", [
-          {cruel: "cruel"},
-          {world: function() { return "world!"; }}
+        '{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}', [
+          {cruel: 'cruel'},
+          {world: function() { return 'world!'; }}
         ],
-        "found it! Goodbye cruel world!!");
+        'found it! Goodbye cruel world!!');
     });
   });
 
   describe('registration', function() {
     it('unregisters', function() {
-      var helpers = handlebarsEnv.helpers;
       handlebarsEnv.helpers = {};
 
       handlebarsEnv.registerHelper('foo', function() {
@@ -230,134 +233,128 @@ describe('helpers', function() {
 
       handlebarsEnv.registerHelper({
         'if': helpers['if'],
-        world: function() { return "world!"; },
-        test_helper: function() { return 'found it!'; }
+        world: function() { return 'world!'; },
+        testHelper: function() { return 'found it!'; }
       });
 
       shouldCompileTo(
-        "{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}",
-        [{cruel: "cruel"}],
-        "found it! Goodbye cruel world!!");
+        '{{testHelper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}',
+        [{cruel: 'cruel'}],
+        'found it! Goodbye cruel world!!');
     });
     it('fails with multiple and args', function() {
       shouldThrow(function() {
         handlebarsEnv.registerHelper({
-          world: function() { return "world!"; },
-          test_helper: function() { return 'found it!'; }
+          world: function() { return 'world!'; },
+          testHelper: function() { return 'found it!'; }
         }, {});
       }, Error, 'Arg not supported with multiple helpers');
     });
   });
 
-  it("decimal number literals work", function() {
-    var string   = 'Message: {{hello -1.2 1.2}}';
-    var hash     = {};
-    var helpers  = {hello: function(times, times2) {
-      if(typeof times !== 'number') { times = "NaN"; }
-      if(typeof times2 !== 'number') { times2 = "NaN"; }
-      return "Hello " + times + " " + times2 + " times";
+  it('decimal number literals work', function() {
+    var string = 'Message: {{hello -1.2 1.2}}';
+    var helpers = {hello: function(times, times2) {
+      if (typeof times !== 'number') { times = 'NaN'; }
+      if (typeof times2 !== 'number') { times2 = 'NaN'; }
+      return 'Hello ' + times + ' ' + times2 + ' times';
     }};
-    shouldCompileTo(string, [hash, helpers], "Message: Hello -1.2 1.2 times", "template with a negative integer literal");
+    shouldCompileTo(string, [{}, helpers], 'Message: Hello -1.2 1.2 times', 'template with a negative integer literal');
   });
 
-  it("negative number literals work", function() {
-    var string   = 'Message: {{hello -12}}';
-    var hash     = {};
-    var helpers  = {hello: function(times) {
-      if(typeof times !== 'number') { times = "NaN"; }
-      return "Hello " + times + " times";
+  it('negative number literals work', function() {
+    var string = 'Message: {{hello -12}}';
+    var helpers = {hello: function(times) {
+      if (typeof times !== 'number') { times = 'NaN'; }
+      return 'Hello ' + times + ' times';
     }};
-    shouldCompileTo(string, [hash, helpers], "Message: Hello -12 times", "template with a negative integer literal");
+    shouldCompileTo(string, [{}, helpers], 'Message: Hello -12 times', 'template with a negative integer literal');
   });
 
-  describe("String literal parameters", function() {
-    it("simple literals work", function() {
-      var string   = 'Message: {{hello "world" 12 true false}}';
-      var hash     = {};
-      var helpers  = {hello: function(param, times, bool1, bool2) {
-        if(typeof times !== 'number') { times = "NaN"; }
-        if(typeof bool1 !== 'boolean') { bool1 = "NaB"; }
-        if(typeof bool2 !== 'boolean') { bool2 = "NaB"; }
-        return "Hello " + param + " " + times + " times: " + bool1 + " " + bool2;
+  describe('String literal parameters', function() {
+    it('simple literals work', function() {
+      var string = 'Message: {{hello "world" 12 true false}}';
+      var helpers = {hello: function(param, times, bool1, bool2) {
+        if (typeof times !== 'number') { times = 'NaN'; }
+        if (typeof bool1 !== 'boolean') { bool1 = 'NaB'; }
+        if (typeof bool2 !== 'boolean') { bool2 = 'NaB'; }
+        return 'Hello ' + param + ' ' + times + ' times: ' + bool1 + ' ' + bool2;
       }};
-      shouldCompileTo(string, [hash, helpers], "Message: Hello world 12 times: true false", "template with a simple String literal");
+      shouldCompileTo(string, [{}, helpers], 'Message: Hello world 12 times: true false', 'template with a simple String literal');
     });
 
-    it("using a quote in the middle of a parameter raises an error", function() {
-      var string   = 'Message: {{hello wo"rld"}}';
+    it('using a quote in the middle of a parameter raises an error', function() {
+      var string = 'Message: {{hello wo"rld"}}';
       shouldThrow(function() {
         CompilerContext.compile(string);
       }, Error);
     });
 
-    it("escaping a String is possible", function(){
-      var string   = 'Message: {{{hello "\\"world\\""}}}';
-      var hash     = {};
-      var helpers = {hello: function(param) { return "Hello " + param; }};
-      shouldCompileTo(string, [hash, helpers], "Message: Hello \"world\"", "template with an escaped String literal");
+    it('escaping a String is possible', function() {
+      var string = 'Message: {{{hello "\\"world\\""}}}';
+      var helpers = {hello: function(param) { return 'Hello ' + param; }};
+      shouldCompileTo(string, [{}, helpers], 'Message: Hello "world"', 'template with an escaped String literal');
     });
 
     it("it works with ' marks", function() {
-      var string   = 'Message: {{{hello "Alan\'s world"}}}';
-      var hash     = {};
-      var helpers = {hello: function(param) { return "Hello " + param; }};
-      shouldCompileTo(string, [hash, helpers], "Message: Hello Alan's world", "template with a ' mark");
+      var string = 'Message: {{{hello "Alan\'s world"}}}';
+      var helpers = {hello: function(param) { return 'Hello ' + param; }};
+      shouldCompileTo(string, [{}, helpers], "Message: Hello Alan's world", "template with a ' mark");
     });
   });
 
-  it("negative number literals work", function() {
-    var string   = 'Message: {{hello -12}}';
-    var hash     = {};
-    var helpers  = {hello: function(times) {
-      if(typeof times !== 'number') { times = "NaN"; }
-      return "Hello " + times + " times";
+  it('negative number literals work', function() {
+    var string = 'Message: {{hello -12}}';
+    var helpers = {hello: function(times) {
+      if (typeof times !== 'number') { times = 'NaN'; }
+      return 'Hello ' + times + ' times';
     }};
-    shouldCompileTo(string, [hash, helpers], "Message: Hello -12 times", "template with a negative integer literal");
+    shouldCompileTo(string, [{}, helpers], 'Message: Hello -12 times', 'template with a negative integer literal');
   });
 
-  describe("multiple parameters", function() {
-    it("simple multi-params work", function() {
-      var string   = 'Message: {{goodbye cruel world}}';
-      var hash     = {cruel: "cruel", world: "world"};
-      var helpers = {goodbye: function(cruel, world) { return "Goodbye " + cruel + " " + world; }};
-      shouldCompileTo(string, [hash, helpers], "Message: Goodbye cruel world", "regular helpers with multiple params");
+  describe('multiple parameters', function() {
+    it('simple multi-params work', function() {
+      var string = 'Message: {{goodbye cruel world}}';
+      var hash = {cruel: 'cruel', world: 'world'};
+      var helpers = {goodbye: function(cruel, world) { return 'Goodbye ' + cruel + ' ' + world; }};
+      shouldCompileTo(string, [hash, helpers], 'Message: Goodbye cruel world', 'regular helpers with multiple params');
     });
 
-    it("block multi-params work", function() {
-      var string   = 'Message: {{#goodbye cruel world}}{{greeting}} {{adj}} {{noun}}{{/goodbye}}';
-      var hash     = {cruel: "cruel", world: "world"};
+    it('block multi-params work', function() {
+      var string = 'Message: {{#goodbye cruel world}}{{greeting}} {{adj}} {{noun}}{{/goodbye}}';
+      var hash = {cruel: 'cruel', world: 'world'};
       var helpers = {goodbye: function(cruel, world, options) {
-        return options.fn({greeting: "Goodbye", adj: cruel, noun: world});
+        return options.fn({greeting: 'Goodbye', adj: cruel, noun: world});
       }};
-      shouldCompileTo(string, [hash, helpers], "Message: Goodbye cruel world", "block helpers with multiple params");
+      shouldCompileTo(string, [hash, helpers], 'Message: Goodbye cruel world', 'block helpers with multiple params');
     });
   });
 
   describe('hash', function() {
-    it("helpers can take an optional hash", function() {
+    it('helpers can take an optional hash', function() {
       var template = CompilerContext.compile('{{goodbye cruel="CRUEL" world="WORLD" times=12}}');
 
       var helpers = {
         goodbye: function(options) {
-          return "GOODBYE " + options.hash.cruel + " " + options.hash.world + " " + options.hash.times + " TIMES";
+          return 'GOODBYE ' + options.hash.cruel + ' ' + options.hash.world + ' ' + options.hash.times + ' TIMES';
         }
       };
 
       var context = {};
 
       var result = template(context, {helpers: helpers});
-      equals(result, "GOODBYE CRUEL WORLD 12 TIMES", "Helper output hash");
+      equals(result, 'GOODBYE CRUEL WORLD 12 TIMES', 'Helper output hash');
     });
 
-    it("helpers can take an optional hash with booleans", function() {
+    it('helpers can take an optional hash with booleans', function() {
       var helpers = {
         goodbye: function(options) {
           if (options.hash.print === true) {
-            return "GOODBYE " + options.hash.cruel + " " + options.hash.world;
+            return 'GOODBYE ' + options.hash.cruel + ' ' + options.hash.world;
           } else if (options.hash.print === false) {
-            return "NOT PRINTING";
+            return 'NOT PRINTING';
           } else {
-            return "THIS SHOULD NOT HAPPEN";
+            return 'THIS SHOULD NOT HAPPEN';
           }
         }
       };
@@ -366,161 +363,161 @@ describe('helpers', function() {
 
       var template = CompilerContext.compile('{{goodbye cruel="CRUEL" world="WORLD" print=true}}');
       var result = template(context, {helpers: helpers});
-      equals(result, "GOODBYE CRUEL WORLD", "Helper output hash");
+      equals(result, 'GOODBYE CRUEL WORLD', 'Helper output hash');
 
       template = CompilerContext.compile('{{goodbye cruel="CRUEL" world="WORLD" print=false}}');
       result = template(context, {helpers: helpers});
-      equals(result, "NOT PRINTING", "Boolean helper parameter honored");
+      equals(result, 'NOT PRINTING', 'Boolean helper parameter honored');
     });
 
-    it("block helpers can take an optional hash", function() {
+    it('block helpers can take an optional hash', function() {
       var template = CompilerContext.compile('{{#goodbye cruel="CRUEL" times=12}}world{{/goodbye}}');
 
       var helpers = {
         goodbye: function(options) {
-          return "GOODBYE " + options.hash.cruel + " " + options.fn(this) + " " + options.hash.times + " TIMES";
+          return 'GOODBYE ' + options.hash.cruel + ' ' + options.fn(this) + ' ' + options.hash.times + ' TIMES';
         }
       };
 
       var result = template({}, {helpers: helpers});
-      equals(result, "GOODBYE CRUEL world 12 TIMES", "Hash parameters output");
+      equals(result, 'GOODBYE CRUEL world 12 TIMES', 'Hash parameters output');
     });
 
-    it("block helpers can take an optional hash with single quoted stings", function() {
-      var template = CompilerContext.compile("{{#goodbye cruel='CRUEL' times=12}}world{{/goodbye}}");
+    it('block helpers can take an optional hash with single quoted stings', function() {
+      var template = CompilerContext.compile('{{#goodbye cruel="CRUEL" times=12}}world{{/goodbye}}');
 
       var helpers = {
         goodbye: function(options) {
-          return "GOODBYE " + options.hash.cruel + " " + options.fn(this) + " " + options.hash.times + " TIMES";
+          return 'GOODBYE ' + options.hash.cruel + ' ' + options.fn(this) + ' ' + options.hash.times + ' TIMES';
         }
       };
 
       var result = template({}, {helpers: helpers});
-      equals(result, "GOODBYE CRUEL world 12 TIMES", "Hash parameters output");
+      equals(result, 'GOODBYE CRUEL world 12 TIMES', 'Hash parameters output');
     });
 
-    it("block helpers can take an optional hash with booleans", function() {
+    it('block helpers can take an optional hash with booleans', function() {
       var helpers = {
         goodbye: function(options) {
           if (options.hash.print === true) {
-            return "GOODBYE " + options.hash.cruel + " " + options.fn(this);
+            return 'GOODBYE ' + options.hash.cruel + ' ' + options.fn(this);
           } else if (options.hash.print === false) {
-            return "NOT PRINTING";
+            return 'NOT PRINTING';
           } else {
-            return "THIS SHOULD NOT HAPPEN";
+            return 'THIS SHOULD NOT HAPPEN';
           }
         }
       };
 
       var template = CompilerContext.compile('{{#goodbye cruel="CRUEL" print=true}}world{{/goodbye}}');
       var result = template({}, {helpers: helpers});
-      equals(result, "GOODBYE CRUEL world", "Boolean hash parameter honored");
+      equals(result, 'GOODBYE CRUEL world', 'Boolean hash parameter honored');
 
       template = CompilerContext.compile('{{#goodbye cruel="CRUEL" print=false}}world{{/goodbye}}');
       result = template({}, {helpers: helpers});
-      equals(result, "NOT PRINTING", "Boolean hash parameter honored");
+      equals(result, 'NOT PRINTING', 'Boolean hash parameter honored');
     });
   });
 
-  describe("helperMissing", function() {
-    it("if a context is not found, helperMissing is used", function() {
+  describe('helperMissing', function() {
+    it('if a context is not found, helperMissing is used', function() {
       shouldThrow(function() {
-          var template = CompilerContext.compile("{{hello}} {{link_to world}}");
+          var template = CompilerContext.compile('{{hello}} {{link_to world}}');
           template({});
-      }, undefined, /Missing helper: 'link_to'/);
+      }, undefined, /Missing helper: "link_to"/);
     });
 
-    it("if a context is not found, custom helperMissing is used", function() {
-      var string = "{{hello}} {{link_to world}}";
-      var context = { hello: "Hello", world: "world" };
+    it('if a context is not found, custom helperMissing is used', function() {
+      var string = '{{hello}} {{link_to world}}';
+      var context = { hello: 'Hello', world: 'world' };
 
       var helpers = {
         helperMissing: function(mesg, options) {
-          if(options.name === "link_to") {
-            return new Handlebars.SafeString("<a>" + mesg + "</a>");
+          if (options.name === 'link_to') {
+            return new Handlebars.SafeString('<a>' + mesg + '</a>');
           }
         }
       };
 
-      shouldCompileTo(string, [context, helpers], "Hello <a>world</a>");
+      shouldCompileTo(string, [context, helpers], 'Hello <a>world</a>');
     });
 
-    it("if a value is not found, custom helperMissing is used", function() {
-      var string = "{{hello}} {{link_to}}";
-      var context = { hello: "Hello", world: "world" };
+    it('if a value is not found, custom helperMissing is used', function() {
+      var string = '{{hello}} {{link_to}}';
+      var context = { hello: 'Hello', world: 'world' };
 
       var helpers = {
         helperMissing: function(options) {
-          if(options.name === "link_to") {
-            return new Handlebars.SafeString("<a>winning</a>");
+          if (options.name === 'link_to') {
+            return new Handlebars.SafeString('<a>winning</a>');
           }
         }
       };
 
-      shouldCompileTo(string, [context, helpers], "Hello <a>winning</a>");
+      shouldCompileTo(string, [context, helpers], 'Hello <a>winning</a>');
     });
   });
 
-  describe("knownHelpers", function() {
-    it("Known helper should render helper", function() {
-      var template = CompilerContext.compile("{{hello}}", {knownHelpers: {"hello" : true}});
+  describe('knownHelpers', function() {
+    it('Known helper should render helper', function() {
+      var template = CompilerContext.compile('{{hello}}', {knownHelpers: {hello: true}});
 
-      var result = template({}, {helpers: {hello: function() { return "foo"; }}});
-      equal(result, "foo", "'foo' should === '" + result);
+      var result = template({}, {helpers: {hello: function() { return 'foo'; }}});
+      equal(result, 'foo', "'foo' should === '" + result);
     });
 
-    it("Unknown helper in knownHelpers only mode should be passed as undefined", function() {
-      var template = CompilerContext.compile("{{typeof hello}}", {knownHelpers: {'typeof': true}, knownHelpersOnly: true});
+    it('Unknown helper in knownHelpers only mode should be passed as undefined', function() {
+      var template = CompilerContext.compile('{{typeof hello}}', {knownHelpers: {'typeof': true}, knownHelpersOnly: true});
 
-      var result = template({}, {helpers: {'typeof': function(arg) { return typeof arg; }, hello: function() { return "foo"; }}});
-      equal(result, "undefined", "'undefined' should === '" + result);
+      var result = template({}, {helpers: {'typeof': function(arg) { return typeof arg; }, hello: function() { return 'foo'; }}});
+      equal(result, 'undefined', "'undefined' should === '" + result);
     });
-    it("Builtin helpers available in knownHelpers only mode", function() {
-      var template = CompilerContext.compile("{{#unless foo}}bar{{/unless}}", {knownHelpersOnly: true});
+    it('Builtin helpers available in knownHelpers only mode', function() {
+      var template = CompilerContext.compile('{{#unless foo}}bar{{/unless}}', {knownHelpersOnly: true});
 
       var result = template({});
-      equal(result, "bar", "'bar' should === '" + result);
+      equal(result, 'bar', "'bar' should === '" + result);
     });
-    it("Field lookup works in knownHelpers only mode", function() {
-      var template = CompilerContext.compile("{{foo}}", {knownHelpersOnly: true});
+    it('Field lookup works in knownHelpers only mode', function() {
+      var template = CompilerContext.compile('{{foo}}', {knownHelpersOnly: true});
 
       var result = template({foo: 'bar'});
-      equal(result, "bar", "'bar' should === '" + result);
+      equal(result, 'bar', "'bar' should === '" + result);
     });
-    it("Conditional blocks work in knownHelpers only mode", function() {
-      var template = CompilerContext.compile("{{#foo}}bar{{/foo}}", {knownHelpersOnly: true});
+    it('Conditional blocks work in knownHelpers only mode', function() {
+      var template = CompilerContext.compile('{{#foo}}bar{{/foo}}', {knownHelpersOnly: true});
 
       var result = template({foo: 'baz'});
-      equal(result, "bar", "'bar' should === '" + result);
+      equal(result, 'bar', "'bar' should === '" + result);
     });
-    it("Invert blocks work in knownHelpers only mode", function() {
-      var template = CompilerContext.compile("{{^foo}}bar{{/foo}}", {knownHelpersOnly: true});
+    it('Invert blocks work in knownHelpers only mode', function() {
+      var template = CompilerContext.compile('{{^foo}}bar{{/foo}}', {knownHelpersOnly: true});
 
       var result = template({foo: false});
-      equal(result, "bar", "'bar' should === '" + result);
+      equal(result, 'bar', "'bar' should === '" + result);
     });
-    it("Functions are bound to the context in knownHelpers only mode", function() {
-      var template = CompilerContext.compile("{{foo}}", {knownHelpersOnly: true});
+    it('Functions are bound to the context in knownHelpers only mode', function() {
+      var template = CompilerContext.compile('{{foo}}', {knownHelpersOnly: true});
       var result = template({foo: function() { return this.bar; }, bar: 'bar'});
-      equal(result, "bar", "'bar' should === '" + result);
+      equal(result, 'bar', "'bar' should === '" + result);
     });
-    it("Unknown helper call in knownHelpers only mode should throw", function() {
+    it('Unknown helper call in knownHelpers only mode should throw', function() {
       shouldThrow(function() {
-        CompilerContext.compile("{{typeof hello}}", {knownHelpersOnly: true});
+        CompilerContext.compile('{{typeof hello}}', {knownHelpersOnly: true});
       }, Error);
     });
   });
 
-  describe("blockHelperMissing", function() {
-    it("lambdas are resolved by blockHelperMissing, not handlebars proper", function() {
-      var string = "{{#truthy}}yep{{/truthy}}";
+  describe('blockHelperMissing', function() {
+    it('lambdas are resolved by blockHelperMissing, not handlebars proper', function() {
+      var string = '{{#truthy}}yep{{/truthy}}';
       var data = { truthy: function() { return true; } };
-      shouldCompileTo(string, data, "yep");
+      shouldCompileTo(string, data, 'yep');
     });
-    it("lambdas resolved by blockHelperMissing are bound to the context", function() {
-      var string = "{{#truthy}}yep{{/truthy}}";
+    it('lambdas resolved by blockHelperMissing are bound to the context', function() {
+      var string = '{{#truthy}}yep{{/truthy}}';
       var boundData = { truthy: function() { return this.truthiness(); }, truthiness: function() { return false; } };
-      shouldCompileTo(string, boundData, "");
+      shouldCompileTo(string, boundData, '');
     });
   });
 
@@ -528,13 +525,13 @@ describe('helpers', function() {
     var context = {};
     var helpers = {
       blockHelperMissing: function() {
-        return 'missing: ' + arguments[arguments.length-1].name;
+        return 'missing: ' + arguments[arguments.length - 1].name;
       },
       helperMissing: function() {
-        return 'helper missing: ' + arguments[arguments.length-1].name;
+        return 'helper missing: ' + arguments[arguments.length - 1].name;
       },
       helper: function() {
-        return 'ran: ' + arguments[arguments.length-1].name;
+        return 'ran: ' + arguments[arguments.length - 1].name;
       }
     };
 
@@ -554,7 +551,7 @@ describe('helpers', function() {
       shouldCompileTo('{{#helper 1}}{{/helper}}', [context, helpers], 'ran: helper');
     });
     it('should include in known helper calls', function() {
-      var template = CompilerContext.compile("{{helper}}", {knownHelpers: {'helper': true}, knownHelpersOnly: true});
+      var template = CompilerContext.compile('{{helper}}', {knownHelpers: {'helper': true}, knownHelpersOnly: true});
 
       equal(template({}, {helpers: helpers}), 'ran: helper');
     });
@@ -569,8 +566,8 @@ describe('helpers', function() {
   });
 
   describe('name conflicts', function() {
-    it("helpers take precedence over same-named context properties", function() {
-      var template = CompilerContext.compile("{{goodbye}} {{cruel world}}");
+    it('helpers take precedence over same-named context properties', function() {
+      var template = CompilerContext.compile('{{goodbye}} {{cruel world}}');
 
       var helpers = {
         goodbye: function() {
@@ -578,21 +575,21 @@ describe('helpers', function() {
         },
 
         cruel: function(world) {
-          return "cruel " + world.toUpperCase();
+          return 'cruel ' + world.toUpperCase();
         }
       };
 
       var context = {
-        goodbye: "goodbye",
-        world: "world"
+        goodbye: 'goodbye',
+        world: 'world'
       };
 
       var result = template(context, {helpers: helpers});
-      equals(result, "GOODBYE cruel WORLD", "Helper executed");
+      equals(result, 'GOODBYE cruel WORLD', 'Helper executed');
     });
 
-    it("helpers take precedence over same-named context properties$", function() {
-      var template = CompilerContext.compile("{{#goodbye}} {{cruel world}}{{/goodbye}}");
+    it('helpers take precedence over same-named context properties$', function() {
+      var template = CompilerContext.compile('{{#goodbye}} {{cruel world}}{{/goodbye}}');
 
       var helpers = {
         goodbye: function(options) {
@@ -600,21 +597,21 @@ describe('helpers', function() {
         },
 
         cruel: function(world) {
-          return "cruel " + world.toUpperCase();
+          return 'cruel ' + world.toUpperCase();
         }
       };
 
       var context = {
-        goodbye: "goodbye",
-        world: "world"
+        goodbye: 'goodbye',
+        world: 'world'
       };
 
       var result = template(context, {helpers: helpers});
-      equals(result, "GOODBYE cruel WORLD", "Helper executed");
+      equals(result, 'GOODBYE cruel WORLD', 'Helper executed');
     });
 
-    it("Scoped names take precedence over helpers", function() {
-      var template = CompilerContext.compile("{{this.goodbye}} {{cruel world}} {{cruel this.goodbye}}");
+    it('Scoped names take precedence over helpers', function() {
+      var template = CompilerContext.compile('{{this.goodbye}} {{cruel world}} {{cruel this.goodbye}}');
 
       var helpers = {
         goodbye: function() {
@@ -622,21 +619,21 @@ describe('helpers', function() {
         },
 
         cruel: function(world) {
-          return "cruel " + world.toUpperCase();
+          return 'cruel ' + world.toUpperCase();
         }
       };
 
       var context = {
-        goodbye: "goodbye",
-        world: "world"
+        goodbye: 'goodbye',
+        world: 'world'
       };
 
       var result = template(context, {helpers: helpers});
-      equals(result, "goodbye cruel WORLD cruel GOODBYE", "Helper not executed");
+      equals(result, 'goodbye cruel WORLD cruel GOODBYE', 'Helper not executed');
     });
 
-    it("Scoped names take precedence over block helpers", function() {
-      var template = CompilerContext.compile("{{#goodbye}} {{cruel world}}{{/goodbye}} {{this.goodbye}}");
+    it('Scoped names take precedence over block helpers', function() {
+      var template = CompilerContext.compile('{{#goodbye}} {{cruel world}}{{/goodbye}} {{this.goodbye}}');
 
       var helpers = {
         goodbye: function(options) {
@@ -644,17 +641,17 @@ describe('helpers', function() {
         },
 
         cruel: function(world) {
-          return "cruel " + world.toUpperCase();
+          return 'cruel ' + world.toUpperCase();
         }
       };
 
       var context = {
-        goodbye: "goodbye",
-        world: "world"
+        goodbye: 'goodbye',
+        world: 'world'
       };
 
       var result = template(context, {helpers: helpers});
-      equals(result, "GOODBYE cruel WORLD goodbye", "Helper executed");
+      equals(result, 'GOODBYE cruel WORLD goodbye', 'Helper executed');
     });
   });
 
diff --git a/spec/javascript-compiler.js b/spec/javascript-compiler.js
index fb7865854..28e698824 100644
--- a/spec/javascript-compiler.js
+++ b/spec/javascript-compiler.js
@@ -1,4 +1,3 @@
-/*global Handlebars, beforeEach, handlebarsEnv, shouldCompileTo */
 describe('javascript-compiler api', function() {
   if (!Handlebars.JavaScriptCompiler) {
     return;
@@ -17,13 +16,15 @@ describe('javascript-compiler api', function() {
       handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = function(parent, name) {
         return parent + '.bar_' + name;
       };
-      shouldCompileTo("{{foo}}", { bar_foo: "food" }, "food");
+      /*eslint-disable camelcase */
+      shouldCompileTo('{{foo}}', { bar_foo: 'food' }, 'food');
+      /*eslint-enable camelcase */
     });
 
     // Tests nameLookup dot vs. bracket behavior.  Bracket is required in certain cases
     // to avoid errors in older browsers.
     it('should handle reserved words', function() {
-      shouldCompileTo("{{foo}} {{~null~}}", { foo: "food" }, "food");
+      shouldCompileTo('{{foo}} {{~null~}}', { foo: 'food' }, 'food');
     });
   });
   describe('#compilerInfo', function() {
@@ -45,7 +46,7 @@ describe('javascript-compiler api', function() {
           throw new Error('It didn\'t work');
         }
       };
-      shouldCompileTo("{{foo}} ", { foo: "food" }, "food ");
+      shouldCompileTo('{{foo}} ', { foo: 'food' }, 'food ');
     });
   });
   describe('buffer', function() {
@@ -65,13 +66,13 @@ describe('javascript-compiler api', function() {
       handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer = function() {
         return this.quotedString('foo_');
       };
-      shouldCompileTo("{{foo}} ", { foo: "food" }, "foo_food ");
+      shouldCompileTo('{{foo}} ', { foo: 'food' }, 'foo_food ');
     });
     it('should allow append buffer override', function() {
       handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = function(string) {
         return $superAppend.call(this, [string, ' + "_foo"']);
       };
-      shouldCompileTo("{{foo}}", { foo: "food" }, "food_foo");
+      shouldCompileTo('{{foo}}', { foo: 'food' }, 'food_foo');
     });
   });
 });
diff --git a/spec/parser.js b/spec/parser.js
index d799e08a2..c37887414 100644
--- a/spec/parser.js
+++ b/spec/parser.js
@@ -1,235 +1,234 @@
-/*global Handlebars, shouldThrow */
 describe('parser', function() {
   if (!Handlebars.print) {
     return;
   }
 
-  function ast_for(template) {
+  function astFor(template) {
     var ast = Handlebars.parse(template);
     return Handlebars.print(ast);
   }
 
   it('parses simple mustaches', function() {
-    equals(ast_for('{{123}}'), "{{ NUMBER{123} [] }}\n");
-    equals(ast_for('{{"foo"}}'), '{{ "foo" [] }}\n');
-    equals(ast_for('{{false}}'), '{{ BOOLEAN{false} [] }}\n');
-    equals(ast_for('{{true}}'), '{{ BOOLEAN{true} [] }}\n');
-    equals(ast_for('{{foo}}'), "{{ PATH:foo [] }}\n");
-    equals(ast_for('{{foo?}}'), "{{ PATH:foo? [] }}\n");
-    equals(ast_for('{{foo_}}'), "{{ PATH:foo_ [] }}\n");
-    equals(ast_for('{{foo-}}'), "{{ PATH:foo- [] }}\n");
-    equals(ast_for('{{foo:}}'), "{{ PATH:foo: [] }}\n");
+    equals(astFor('{{123}}'), '{{ NUMBER{123} [] }}\n');
+    equals(astFor('{{"foo"}}'), '{{ "foo" [] }}\n');
+    equals(astFor('{{false}}'), '{{ BOOLEAN{false} [] }}\n');
+    equals(astFor('{{true}}'), '{{ BOOLEAN{true} [] }}\n');
+    equals(astFor('{{foo}}'), '{{ PATH:foo [] }}\n');
+    equals(astFor('{{foo?}}'), '{{ PATH:foo? [] }}\n');
+    equals(astFor('{{foo_}}'), '{{ PATH:foo_ [] }}\n');
+    equals(astFor('{{foo-}}'), '{{ PATH:foo- [] }}\n');
+    equals(astFor('{{foo:}}'), '{{ PATH:foo: [] }}\n');
   });
 
   it('parses simple mustaches with data', function() {
-    equals(ast_for("{{@foo}}"), "{{ @PATH:foo [] }}\n");
+    equals(astFor('{{@foo}}'), '{{ @PATH:foo [] }}\n');
   });
 
   it('parses simple mustaches with data paths', function() {
-    equals(ast_for("{{@../foo}}"), "{{ @PATH:foo [] }}\n");
+    equals(astFor('{{@../foo}}'), '{{ @PATH:foo [] }}\n');
   });
 
   it('parses mustaches with paths', function() {
-    equals(ast_for("{{foo/bar}}"), "{{ PATH:foo/bar [] }}\n");
+    equals(astFor('{{foo/bar}}'), '{{ PATH:foo/bar [] }}\n');
   });
 
   it('parses mustaches with this/foo', function() {
-    equals(ast_for("{{this/foo}}"), "{{ PATH:foo [] }}\n");
+    equals(astFor('{{this/foo}}'), '{{ PATH:foo [] }}\n');
   });
 
   it('parses mustaches with - in a path', function() {
-    equals(ast_for("{{foo-bar}}"), "{{ PATH:foo-bar [] }}\n");
+    equals(astFor('{{foo-bar}}'), '{{ PATH:foo-bar [] }}\n');
   });
 
   it('parses mustaches with parameters', function() {
-    equals(ast_for("{{foo bar}}"), "{{ PATH:foo [PATH:bar] }}\n");
+    equals(astFor('{{foo bar}}'), '{{ PATH:foo [PATH:bar] }}\n');
   });
 
   it('parses mustaches with string parameters', function() {
-    equals(ast_for("{{foo bar \"baz\" }}"), '{{ PATH:foo [PATH:bar, "baz"] }}\n');
+    equals(astFor('{{foo bar \"baz\" }}'), '{{ PATH:foo [PATH:bar, "baz"] }}\n');
   });
 
   it('parses mustaches with NUMBER parameters', function() {
-    equals(ast_for("{{foo 1}}"), "{{ PATH:foo [NUMBER{1}] }}\n");
+    equals(astFor('{{foo 1}}'), '{{ PATH:foo [NUMBER{1}] }}\n');
   });
 
   it('parses mustaches with BOOLEAN parameters', function() {
-    equals(ast_for("{{foo true}}"), "{{ PATH:foo [BOOLEAN{true}] }}\n");
-    equals(ast_for("{{foo false}}"), "{{ PATH:foo [BOOLEAN{false}] }}\n");
+    equals(astFor('{{foo true}}'), '{{ PATH:foo [BOOLEAN{true}] }}\n');
+    equals(astFor('{{foo false}}'), '{{ PATH:foo [BOOLEAN{false}] }}\n');
   });
 
   it('parses mustaches with undefined and null paths', function() {
-    equals(ast_for("{{undefined}}"), "{{ UNDEFINED [] }}\n");
-    equals(ast_for("{{null}}"), "{{ NULL [] }}\n");
+    equals(astFor('{{undefined}}'), '{{ UNDEFINED [] }}\n');
+    equals(astFor('{{null}}'), '{{ NULL [] }}\n');
   });
   it('parses mustaches with undefined and null parameters', function() {
-    equals(ast_for("{{foo undefined null}}"), "{{ PATH:foo [UNDEFINED, NULL] }}\n");
+    equals(astFor('{{foo undefined null}}'), '{{ PATH:foo [UNDEFINED, NULL] }}\n');
   });
 
   it('parses mutaches with DATA parameters', function() {
-    equals(ast_for("{{foo @bar}}"), "{{ PATH:foo [@PATH:bar] }}\n");
+    equals(astFor('{{foo @bar}}'), '{{ PATH:foo [@PATH:bar] }}\n');
   });
 
   it('parses mustaches with hash arguments', function() {
-    equals(ast_for("{{foo bar=baz}}"), "{{ PATH:foo [] HASH{bar=PATH:baz} }}\n");
-    equals(ast_for("{{foo bar=1}}"), "{{ PATH:foo [] HASH{bar=NUMBER{1}} }}\n");
-    equals(ast_for("{{foo bar=true}}"), "{{ PATH:foo [] HASH{bar=BOOLEAN{true}} }}\n");
-    equals(ast_for("{{foo bar=false}}"), "{{ PATH:foo [] HASH{bar=BOOLEAN{false}} }}\n");
-    equals(ast_for("{{foo bar=@baz}}"), "{{ PATH:foo [] HASH{bar=@PATH:baz} }}\n");
+    equals(astFor('{{foo bar=baz}}'), '{{ PATH:foo [] HASH{bar=PATH:baz} }}\n');
+    equals(astFor('{{foo bar=1}}'), '{{ PATH:foo [] HASH{bar=NUMBER{1}} }}\n');
+    equals(astFor('{{foo bar=true}}'), '{{ PATH:foo [] HASH{bar=BOOLEAN{true}} }}\n');
+    equals(astFor('{{foo bar=false}}'), '{{ PATH:foo [] HASH{bar=BOOLEAN{false}} }}\n');
+    equals(astFor('{{foo bar=@baz}}'), '{{ PATH:foo [] HASH{bar=@PATH:baz} }}\n');
 
-    equals(ast_for("{{foo bar=baz bat=bam}}"), "{{ PATH:foo [] HASH{bar=PATH:baz, bat=PATH:bam} }}\n");
-    equals(ast_for("{{foo bar=baz bat=\"bam\"}}"), '{{ PATH:foo [] HASH{bar=PATH:baz, bat="bam"} }}\n');
+    equals(astFor('{{foo bar=baz bat=bam}}'), '{{ PATH:foo [] HASH{bar=PATH:baz, bat=PATH:bam} }}\n');
+    equals(astFor('{{foo bar=baz bat="bam"}}'), '{{ PATH:foo [] HASH{bar=PATH:baz, bat="bam"} }}\n');
 
-    equals(ast_for("{{foo bat='bam'}}"), '{{ PATH:foo [] HASH{bat="bam"} }}\n');
+    equals(astFor("{{foo bat='bam'}}"), '{{ PATH:foo [] HASH{bat="bam"} }}\n');
 
-    equals(ast_for("{{foo omg bar=baz bat=\"bam\"}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n');
-    equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=1}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n');
-    equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=true}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n');
-    equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=false}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n');
+    equals(astFor('{{foo omg bar=baz bat=\"bam\"}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n');
+    equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=1}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n');
+    equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=true}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n');
+    equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=false}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n');
   });
 
   it('parses contents followed by a mustache', function() {
-    equals(ast_for("foo bar {{baz}}"), "CONTENT[ \'foo bar \' ]\n{{ PATH:baz [] }}\n");
+    equals(astFor('foo bar {{baz}}'), 'CONTENT[ \'foo bar \' ]\n{{ PATH:baz [] }}\n');
   });
 
   it('parses a partial', function() {
-    equals(ast_for("{{> foo }}"), "{{> PARTIAL:foo }}\n");
-    equals(ast_for("{{> 'foo' }}"), "{{> PARTIAL:foo }}\n");
-    equals(ast_for("{{> 1 }}"), "{{> PARTIAL:1 }}\n");
+    equals(astFor('{{> foo }}'), '{{> PARTIAL:foo }}\n');
+    equals(astFor('{{> "foo" }}'), '{{> PARTIAL:foo }}\n');
+    equals(astFor('{{> 1 }}'), '{{> PARTIAL:1 }}\n');
   });
 
   it('parses a partial with context', function() {
-    equals(ast_for("{{> foo bar}}"), "{{> PARTIAL:foo PATH:bar }}\n");
+    equals(astFor('{{> foo bar}}'), '{{> PARTIAL:foo PATH:bar }}\n');
   });
 
   it('parses a partial with hash', function() {
-    equals(ast_for("{{> foo bar=bat}}"), "{{> PARTIAL:foo HASH{bar=PATH:bat} }}\n");
+    equals(astFor('{{> foo bar=bat}}'), '{{> PARTIAL:foo HASH{bar=PATH:bat} }}\n');
   });
 
   it('parses a partial with context and hash', function() {
-    equals(ast_for("{{> foo bar bat=baz}}"), "{{> PARTIAL:foo PATH:bar HASH{bat=PATH:baz} }}\n");
+    equals(astFor('{{> foo bar bat=baz}}'), '{{> PARTIAL:foo PATH:bar HASH{bat=PATH:baz} }}\n');
   });
 
   it('parses a partial with a complex name', function() {
-    equals(ast_for("{{> shared/partial?.bar}}"), "{{> PARTIAL:shared/partial?.bar }}\n");
+    equals(astFor('{{> shared/partial?.bar}}'), '{{> PARTIAL:shared/partial?.bar }}\n');
   });
 
   it('parses a comment', function() {
-    equals(ast_for("{{! this is a comment }}"), "{{! ' this is a comment ' }}\n");
+    equals(astFor('{{! this is a comment }}'), "{{! ' this is a comment ' }}\n");
   });
 
   it('parses a multi-line comment', function() {
-    equals(ast_for("{{!\nthis is a multi-line comment\n}}"), "{{! \'\nthis is a multi-line comment\n\' }}\n");
+    equals(astFor('{{!\nthis is a multi-line comment\n}}'), "{{! \'\nthis is a multi-line comment\n\' }}\n");
   });
 
   it('parses an inverse section', function() {
-    equals(ast_for("{{#foo}} bar {{^}} baz {{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    CONTENT[ ' bar ' ]\n  {{^}}\n    CONTENT[ ' baz ' ]\n");
+    equals(astFor('{{#foo}} bar {{^}} baz {{/foo}}'), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    CONTENT[ ' bar ' ]\n  {{^}}\n    CONTENT[ ' baz ' ]\n");
   });
 
   it('parses an inverse (else-style) section', function() {
-    equals(ast_for("{{#foo}} bar {{else}} baz {{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    CONTENT[ ' bar ' ]\n  {{^}}\n    CONTENT[ ' baz ' ]\n");
+    equals(astFor('{{#foo}} bar {{else}} baz {{/foo}}'), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    CONTENT[ ' bar ' ]\n  {{^}}\n    CONTENT[ ' baz ' ]\n");
   });
 
   it('parses multiple inverse sections', function() {
-    equals(ast_for("{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    CONTENT[ ' bar ' ]\n  {{^}}\n    BLOCK:\n      PATH:if [PATH:bar]\n      PROGRAM:\n      {{^}}\n        CONTENT[ ' baz ' ]\n");
+    equals(astFor('{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}'), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    CONTENT[ ' bar ' ]\n  {{^}}\n    BLOCK:\n      PATH:if [PATH:bar]\n      PROGRAM:\n      {{^}}\n        CONTENT[ ' baz ' ]\n");
   });
 
   it('parses empty blocks', function() {
-    equals(ast_for("{{#foo}}{{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n");
+    equals(astFor('{{#foo}}{{/foo}}'), 'BLOCK:\n  PATH:foo []\n  PROGRAM:\n');
   });
 
   it('parses empty blocks with empty inverse section', function() {
-    equals(ast_for("{{#foo}}{{^}}{{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n  {{^}}\n");
+    equals(astFor('{{#foo}}{{^}}{{/foo}}'), 'BLOCK:\n  PATH:foo []\n  PROGRAM:\n  {{^}}\n');
   });
 
   it('parses empty blocks with empty inverse (else-style) section', function() {
-    equals(ast_for("{{#foo}}{{else}}{{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n  {{^}}\n");
+    equals(astFor('{{#foo}}{{else}}{{/foo}}'), 'BLOCK:\n  PATH:foo []\n  PROGRAM:\n  {{^}}\n');
   });
 
   it('parses non-empty blocks with empty inverse section', function() {
-    equals(ast_for("{{#foo}} bar {{^}}{{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    CONTENT[ ' bar ' ]\n  {{^}}\n");
+    equals(astFor('{{#foo}} bar {{^}}{{/foo}}'), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    CONTENT[ ' bar ' ]\n  {{^}}\n");
   });
 
   it('parses non-empty blocks with empty inverse (else-style) section', function() {
-    equals(ast_for("{{#foo}} bar {{else}}{{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    CONTENT[ ' bar ' ]\n  {{^}}\n");
+    equals(astFor('{{#foo}} bar {{else}}{{/foo}}'), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    CONTENT[ ' bar ' ]\n  {{^}}\n");
   });
 
   it('parses empty blocks with non-empty inverse section', function() {
-    equals(ast_for("{{#foo}}{{^}} bar {{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n  {{^}}\n    CONTENT[ ' bar ' ]\n");
+    equals(astFor('{{#foo}}{{^}} bar {{/foo}}'), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n  {{^}}\n    CONTENT[ ' bar ' ]\n");
   });
 
   it('parses empty blocks with non-empty inverse (else-style) section', function() {
-    equals(ast_for("{{#foo}}{{else}} bar {{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n  {{^}}\n    CONTENT[ ' bar ' ]\n");
+    equals(astFor('{{#foo}}{{else}} bar {{/foo}}'), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n  {{^}}\n    CONTENT[ ' bar ' ]\n");
   });
 
   it('parses a standalone inverse section', function() {
-    equals(ast_for("{{^foo}}bar{{/foo}}"), "BLOCK:\n  PATH:foo []\n  {{^}}\n    CONTENT[ 'bar' ]\n");
+    equals(astFor('{{^foo}}bar{{/foo}}'), "BLOCK:\n  PATH:foo []\n  {{^}}\n    CONTENT[ 'bar' ]\n");
   });
   it('throws on old inverse section', function() {
     shouldThrow(function() {
-      ast_for("{{else foo}}bar{{/foo}}");
+      astFor('{{else foo}}bar{{/foo}}');
     }, Error);
   });
 
   it('parses block with block params', function() {
-    equals(ast_for("{{#foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    BLOCK PARAMS: [ bar baz ]\n    CONTENT[ 'content' ]\n");
+    equals(astFor('{{#foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n    BLOCK PARAMS: [ bar baz ]\n    CONTENT[ 'content' ]\n");
   });
 
   it('parses inverse block with block params', function() {
-    equals(ast_for("{{^foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n  PATH:foo []\n  {{^}}\n    BLOCK PARAMS: [ bar baz ]\n    CONTENT[ 'content' ]\n");
+    equals(astFor('{{^foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n  PATH:foo []\n  {{^}}\n    BLOCK PARAMS: [ bar baz ]\n    CONTENT[ 'content' ]\n");
   });
   it('parses chained inverse block with block params', function() {
-    equals(ast_for("{{#foo}}{{else foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n  {{^}}\n    BLOCK:\n      PATH:foo []\n      PROGRAM:\n        BLOCK PARAMS: [ bar baz ]\n        CONTENT[ 'content' ]\n");
+    equals(astFor('{{#foo}}{{else foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n  PATH:foo []\n  PROGRAM:\n  {{^}}\n    BLOCK:\n      PATH:foo []\n      PROGRAM:\n        BLOCK PARAMS: [ bar baz ]\n        CONTENT[ 'content' ]\n");
   });
-  it("raises if there's a Parse error", function() {
+  it('raises if there\'s a Parse error', function() {
     shouldThrow(function() {
-      ast_for("foo{{^}}bar");
+      astFor('foo{{^}}bar');
     }, Error, /Parse error on line 1/);
     shouldThrow(function() {
-      ast_for("{{foo}");
+      astFor('{{foo}');
     }, Error, /Parse error on line 1/);
     shouldThrow(function() {
-      ast_for("{{foo &}}");
+      astFor('{{foo &}}');
     }, Error, /Parse error on line 1/);
     shouldThrow(function() {
-      ast_for("{{#goodbyes}}{{/hellos}}");
+      astFor('{{#goodbyes}}{{/hellos}}');
     }, Error, /goodbyes doesn't match hellos/);
 
     shouldThrow(function() {
-      ast_for("{{{{goodbyes}}}} {{{{/hellos}}}}");
+      astFor('{{{{goodbyes}}}} {{{{/hellos}}}}');
     }, Error, /goodbyes doesn't match hellos/);
   });
 
   it('should handle invalid paths', function() {
     shouldThrow(function() {
-      ast_for("{{foo/../bar}}");
+      astFor('{{foo/../bar}}');
     }, Error, /Invalid path: foo\/\.\. - 1:2/);
     shouldThrow(function() {
-      ast_for("{{foo/./bar}}");
+      astFor('{{foo/./bar}}');
     }, Error, /Invalid path: foo\/\. - 1:2/);
     shouldThrow(function() {
-      ast_for("{{foo/this/bar}}");
+      astFor('{{foo/this/bar}}');
     }, Error, /Invalid path: foo\/this - 1:2/);
   });
 
   it('knows how to report the correct line number in errors', function() {
     shouldThrow(function() {
-      ast_for("hello\nmy\n{{foo}");
+      astFor('hello\nmy\n{{foo}');
     }, Error, /Parse error on line 3/);
     shouldThrow(function() {
-      ast_for("hello\n\nmy\n\n{{foo}");
+      astFor('hello\n\nmy\n\n{{foo}');
     }, Error, /Parse error on line 5/);
   });
 
   it('knows how to report the correct line number in errors when the first character is a newline', function() {
     shouldThrow(function() {
-      ast_for("\n\nhello\n\nmy\n\n{{foo}");
+      astFor('\n\nhello\n\nmy\n\n{{foo}');
     }, Error, /Parse error on line 7/);
   });
 
   describe('externally compiled AST', function() {
     it('can pass through an already-compiled AST', function() {
-      equals(ast_for(new Handlebars.AST.Program([new Handlebars.AST.ContentStatement("Hello")], null)), "CONTENT[ \'Hello\' ]\n");
+      equals(astFor(new Handlebars.AST.Program([new Handlebars.AST.ContentStatement('Hello')], null)), 'CONTENT[ \'Hello\' ]\n');
     });
   });
 });
diff --git a/spec/partials.js b/spec/partials.js
index 0c9e0f6dc..22d2dc959 100644
--- a/spec/partials.js
+++ b/spec/partials.js
@@ -1,11 +1,10 @@
-/*global CompilerContext, Handlebars, handlebarsEnv, shouldCompileTo, shouldCompileToWithPartials, shouldThrow */
 describe('partials', function() {
   it('basic partials', function() {
     var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
     var partial = '{{name}} ({{url}}) ';
     var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
     shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
-    shouldCompileToWithPartials(string, [hash, {}, {dude: partial},,false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
+    shouldCompileToWithPartials(string, [hash, {}, {dude: partial},, false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
   });
 
   it('dynamic partials', function() {
@@ -18,7 +17,7 @@ describe('partials', function() {
       }
     };
     shouldCompileToWithPartials(string, [hash, helpers, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
-    shouldCompileToWithPartials(string, [hash, helpers, {dude: partial},,false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
+    shouldCompileToWithPartials(string, [hash, helpers, {dude: partial},, false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ');
   });
   it('failing dynamic partials', function() {
     var string = 'Dudes: {{#dudes}}{{> (partial)}}{{/dudes}}';
@@ -34,19 +33,19 @@ describe('partials', function() {
     }, Handlebars.Exception, 'The partial missing could not be found');
   });
 
-  it("partials with context", function() {
-    var string = "Dudes: {{>dude dudes}}";
-    var partial = "{{#this}}{{name}} ({{url}}) {{/this}}";
-    var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
-    shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes: Yehuda (http://yehuda) Alan (http://alan) ",
-                    "Partials can be passed a context");
+  it('partials with context', function() {
+    var string = 'Dudes: {{>dude dudes}}';
+    var partial = '{{#this}}{{name}} ({{url}}) {{/this}}';
+    var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
+    shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ',
+                    'Partials can be passed a context');
   });
 
-  it("partials with undefined context", function() {
-    var string = "Dudes: {{>dude dudes}}";
-    var partial = "{{foo}} Empty";
+  it('partials with undefined context', function() {
+    var string = 'Dudes: {{>dude dudes}}';
+    var partial = '{{foo}} Empty';
     var hash = {};
-    shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes:  Empty");
+    shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes:  Empty');
   });
 
   it('partials with duplicate parameters', function() {
@@ -55,133 +54,133 @@ describe('partials', function() {
     }, Error, 'Unsupported number of partial arguments: 2 - 1:7');
   });
 
-  it("partials with parameters", function() {
-    var string = "Dudes: {{#dudes}}{{> dude others=..}}{{/dudes}}";
-    var partial = "{{others.foo}}{{name}} ({{url}}) ";
-    var hash = {foo: 'bar', dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
-    shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes: barYehuda (http://yehuda) barAlan (http://alan) ",
-                    "Basic partials output based on current context.");
+  it('partials with parameters', function() {
+    var string = 'Dudes: {{#dudes}}{{> dude others=..}}{{/dudes}}';
+    var partial = '{{others.foo}}{{name}} ({{url}}) ';
+    var hash = {foo: 'bar', dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
+    shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: barYehuda (http://yehuda) barAlan (http://alan) ',
+                    'Basic partials output based on current context.');
   });
 
-  it("partial in a partial", function() {
-    var string = "Dudes: {{#dudes}}{{>dude}}{{/dudes}}";
-    var dude = "{{name}} {{> url}} ";
-    var url = "<a href='{{url}}'>{{url}}</a>";
-    var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
-    shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}], true, "Dudes: Yehuda <a href='http://yehuda'>http://yehuda</a> Alan <a href='http://alan'>http://alan</a> ", "Partials are rendered inside of other partials");
+  it('partial in a partial', function() {
+    var string = 'Dudes: {{#dudes}}{{>dude}}{{/dudes}}';
+    var dude = '{{name}} {{> url}} ';
+    var url = '<a href="{{url}}">{{url}}</a>';
+    var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
+    shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}], true, 'Dudes: Yehuda <a href="http://yehuda">http://yehuda</a> Alan <a href="http://alan">http://alan</a> ', 'Partials are rendered inside of other partials');
   });
 
-  it("rendering undefined partial throws an exception", function() {
+  it('rendering undefined partial throws an exception', function() {
     shouldThrow(function() {
-      var template = CompilerContext.compile("{{> whatever}}");
+      var template = CompilerContext.compile('{{> whatever}}');
       template();
     }, Handlebars.Exception, 'The partial whatever could not be found');
   });
 
-  it("registering undefined partial throws an exception", function() {
+  it('registering undefined partial throws an exception', function() {
     shouldThrow(function() {
       var undef;
       handlebarsEnv.registerPartial('undefined_test', undef);
     }, Handlebars.Exception, 'Attempting to register a partial as undefined');
   });
 
-  it("rendering template partial in vm mode throws an exception", function() {
+  it('rendering template partial in vm mode throws an exception', function() {
     shouldThrow(function() {
-      var template = CompilerContext.compile("{{> whatever}}");
+      var template = CompilerContext.compile('{{> whatever}}');
       template();
     }, Handlebars.Exception, 'The partial whatever could not be found');
   });
 
-  it("rendering function partial in vm mode", function() {
-    var string = "Dudes: {{#dudes}}{{> dude}}{{/dudes}}";
-    var partial = function(context) {
+  it('rendering function partial in vm mode', function() {
+    var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
+    function partial(context) {
       return context.name + ' (' + context.url + ') ';
-    };
-    var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
-    shouldCompileTo(string, [hash, {}, {dude: partial}], "Dudes: Yehuda (http://yehuda) Alan (http://alan) ",
-                    "Function partials output based in VM.");
+    }
+    var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
+    shouldCompileTo(string, [hash, {}, {dude: partial}], 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ',
+                    'Function partials output based in VM.');
   });
 
-  it("GH-14: a partial preceding a selector", function() {
-    var string = "Dudes: {{>dude}} {{another_dude}}";
-    var dude = "{{name}}";
-    var hash = {name:"Jeepers", another_dude:"Creepers"};
-    shouldCompileToWithPartials(string, [hash, {}, {dude:dude}], true, "Dudes: Jeepers Creepers", "Regular selectors can follow a partial");
+  it('GH-14: a partial preceding a selector', function() {
+    var string = 'Dudes: {{>dude}} {{anotherDude}}';
+    var dude = '{{name}}';
+    var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
+    shouldCompileToWithPartials(string, [hash, {}, {dude: dude}], true, 'Dudes: Jeepers Creepers', 'Regular selectors can follow a partial');
   });
 
-  it("Partials with slash paths", function() {
-    var string = "Dudes: {{> shared/dude}}";
-    var dude = "{{name}}";
-    var hash = {name:"Jeepers", another_dude:"Creepers"};
-    shouldCompileToWithPartials(string, [hash, {}, {'shared/dude':dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
+  it('Partials with slash paths', function() {
+    var string = 'Dudes: {{> shared/dude}}';
+    var dude = '{{name}}';
+    var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
+    shouldCompileToWithPartials(string, [hash, {}, {'shared/dude': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
   });
 
-  it("Partials with slash and point paths", function() {
-    var string = "Dudes: {{> shared/dude.thing}}";
-    var dude = "{{name}}";
-    var hash = {name:"Jeepers", another_dude:"Creepers"};
-    shouldCompileToWithPartials(string, [hash, {}, {'shared/dude.thing':dude}], true, "Dudes: Jeepers", "Partials can use literal with points in paths");
+  it('Partials with slash and point paths', function() {
+    var string = 'Dudes: {{> shared/dude.thing}}';
+    var dude = '{{name}}';
+    var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
+    shouldCompileToWithPartials(string, [hash, {}, {'shared/dude.thing': dude}], true, 'Dudes: Jeepers', 'Partials can use literal with points in paths');
   });
 
-  it("Global Partials", function() {
-    handlebarsEnv.registerPartial('global_test', '{{another_dude}}');
+  it('Global Partials', function() {
+    handlebarsEnv.registerPartial('globalTest', '{{anotherDude}}');
 
-    var string = "Dudes: {{> shared/dude}} {{> global_test}}";
-    var dude = "{{name}}";
-    var hash = {name:"Jeepers", another_dude:"Creepers"};
-    shouldCompileToWithPartials(string, [hash, {}, {'shared/dude':dude}], true, "Dudes: Jeepers Creepers", "Partials can use globals or passed");
+    var string = 'Dudes: {{> shared/dude}} {{> globalTest}}';
+    var dude = '{{name}}';
+    var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
+    shouldCompileToWithPartials(string, [hash, {}, {'shared/dude': dude}], true, 'Dudes: Jeepers Creepers', 'Partials can use globals or passed');
 
-    handlebarsEnv.unregisterPartial('global_test');
-    equals(handlebarsEnv.partials.global_test, undefined);
+    handlebarsEnv.unregisterPartial('globalTest');
+    equals(handlebarsEnv.partials.globalTest, undefined);
   });
 
-  it("Multiple partial registration", function() {
+  it('Multiple partial registration', function() {
     handlebarsEnv.registerPartial({
       'shared/dude': '{{name}}',
-      global_test: '{{another_dude}}'
+      globalTest: '{{anotherDude}}'
     });
 
-    var string = "Dudes: {{> shared/dude}} {{> global_test}}";
-    var hash = {name:"Jeepers", another_dude:"Creepers"};
-    shouldCompileToWithPartials(string, [hash], true, "Dudes: Jeepers Creepers", "Partials can use globals or passed");
+    var string = 'Dudes: {{> shared/dude}} {{> globalTest}}';
+    var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
+    shouldCompileToWithPartials(string, [hash], true, 'Dudes: Jeepers Creepers', 'Partials can use globals or passed');
   });
 
-  it("Partials with integer path", function() {
-    var string = "Dudes: {{> 404}}";
-    var dude = "{{name}}";
-    var hash = {name:"Jeepers", another_dude:"Creepers"};
-    shouldCompileToWithPartials(string, [hash, {}, {404:dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
+  it('Partials with integer path', function() {
+    var string = 'Dudes: {{> 404}}';
+    var dude = '{{name}}';
+    var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
+    shouldCompileToWithPartials(string, [hash, {}, {404: dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
   });
 
-  it("Partials with complex path", function() {
-    var string = "Dudes: {{> 404/asdf?.bar}}";
-    var dude = "{{name}}";
-    var hash = {name:"Jeepers", another_dude:"Creepers"};
-    shouldCompileToWithPartials(string, [hash, {}, {'404/asdf?.bar':dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
+  it('Partials with complex path', function() {
+    var string = 'Dudes: {{> 404/asdf?.bar}}';
+    var dude = '{{name}}';
+    var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
+    shouldCompileToWithPartials(string, [hash, {}, {'404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
   });
 
-  it("Partials with escaped", function() {
-    var string = "Dudes: {{> [+404/asdf?.bar]}}";
-    var dude = "{{name}}";
-    var hash = {name:"Jeepers", another_dude:"Creepers"};
-    shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar':dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
+  it('Partials with escaped', function() {
+    var string = 'Dudes: {{> [+404/asdf?.bar]}}';
+    var dude = '{{name}}';
+    var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
+    shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
   });
 
-  it("Partials with string", function() {
-    var string = "Dudes: {{> \"+404/asdf?.bar\"}}";
-    var dude = "{{name}}";
-    var hash = {name:"Jeepers", another_dude:"Creepers"};
-    shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar':dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
+  it('Partials with string', function() {
+    var string = 'Dudes: {{> \'+404/asdf?.bar\'}}';
+    var dude = '{{name}}';
+    var hash = {name: 'Jeepers', anotherDude: 'Creepers'};
+    shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths');
   });
 
   it('should handle empty partial', function() {
-    var string = "Dudes: {{#dudes}}{{> dude}}{{/dudes}}";
-    var partial = "";
-    var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
-    shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes: ");
+    var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}';
+    var partial = '';
+    var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
+    shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: ');
   });
 
-  it("throw on missing partial", function() {
+  it('throw on missing partial', function() {
     var compile = handlebarsEnv.compile;
     handlebarsEnv.compile = undefined;
     shouldThrow(function() {
@@ -200,28 +199,28 @@ describe('partials', function() {
   });
 
   describe('standalone partials', function() {
-    it("indented partials", function() {
-      var string = "Dudes:\n{{#dudes}}\n  {{>dude}}\n{{/dudes}}";
-      var dude = "{{name}}\n";
-      var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
+    it('indented partials', function() {
+      var string = 'Dudes:\n{{#dudes}}\n  {{>dude}}\n{{/dudes}}';
+      var dude = '{{name}}\n';
+      var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
       shouldCompileToWithPartials(string, [hash, {}, {dude: dude}], true,
-            "Dudes:\n  Yehuda\n  Alan\n");
+            'Dudes:\n  Yehuda\n  Alan\n');
     });
-    it("nested indented partials", function() {
-      var string = "Dudes:\n{{#dudes}}\n  {{>dude}}\n{{/dudes}}";
-      var dude = "{{name}}\n {{> url}}";
-      var url = "{{url}}!\n";
-      var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
+    it('nested indented partials', function() {
+      var string = 'Dudes:\n{{#dudes}}\n  {{>dude}}\n{{/dudes}}';
+      var dude = '{{name}}\n {{> url}}';
+      var url = '{{url}}!\n';
+      var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
       shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}], true,
-            "Dudes:\n  Yehuda\n   http://yehuda!\n  Alan\n   http://alan!\n");
+            'Dudes:\n  Yehuda\n   http://yehuda!\n  Alan\n   http://alan!\n');
     });
-    it("prevent nested indented partials", function() {
-      var string = "Dudes:\n{{#dudes}}\n  {{>dude}}\n{{/dudes}}";
-      var dude = "{{name}}\n {{> url}}";
-      var url = "{{url}}!\n";
-      var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]};
+    it('prevent nested indented partials', function() {
+      var string = 'Dudes:\n{{#dudes}}\n  {{>dude}}\n{{/dudes}}';
+      var dude = '{{name}}\n {{> url}}';
+      var url = '{{url}}!\n';
+      var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
       shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}, {preventIndent: true}], true,
-            "Dudes:\n  Yehuda\n http://yehuda!\n  Alan\n http://alan!\n");
+            'Dudes:\n  Yehuda\n http://yehuda!\n  Alan\n http://alan!\n');
     });
   });
 
diff --git a/spec/precompiler.js b/spec/precompiler.js
index cbbfdf7ea..f877c2911 100644
--- a/spec/precompiler.js
+++ b/spec/precompiler.js
@@ -1,6 +1,4 @@
-/*global shouldThrow */
-
-
+/*eslint-disable no-console */
 describe('precompiler', function() {
   // NOP Under non-node environments
   if (typeof process === 'undefined') {
diff --git a/spec/regressions.js b/spec/regressions.js
index 84b9d0c52..247c1c9b3 100644
--- a/spec/regressions.js
+++ b/spec/regressions.js
@@ -1,26 +1,34 @@
-/*global CompilerContext, shouldCompileTo, shouldThrow */
 describe('Regressions', function() {
-  it("GH-94: Cannot read property of undefined", function() {
-    var data = {"books":[{"title":"The origin of species","author":{"name":"Charles Darwin"}},{"title":"Lazarillo de Tormes"}]};
-    var string = "{{#books}}{{title}}{{author.name}}{{/books}}";
-    shouldCompileTo(string, data, "The origin of speciesCharles DarwinLazarillo de Tormes",
-                    "Renders without an undefined property error");
+  it('GH-94: Cannot read property of undefined', function() {
+    var data = {
+      'books': [{
+        'title': 'The origin of species',
+        'author': {
+          'name': 'Charles Darwin'
+        }
+      }, {
+        'title': 'Lazarillo de Tormes'
+      }]
+    };
+    var string = '{{#books}}{{title}}{{author.name}}{{/books}}';
+    shouldCompileTo(string, data, 'The origin of speciesCharles DarwinLazarillo de Tormes',
+                    'Renders without an undefined property error');
   });
 
   it("GH-150: Inverted sections print when they shouldn't", function() {
-    var string = "{{^set}}not set{{/set}} :: {{#set}}set{{/set}}";
+    var string = '{{^set}}not set{{/set}} :: {{#set}}set{{/set}}';
 
-    shouldCompileTo(string, {}, "not set :: ", "inverted sections run when property isn't present in context");
-    shouldCompileTo(string, {set: undefined}, "not set :: ", "inverted sections run when property is undefined");
-    shouldCompileTo(string, {set: false}, "not set :: ", "inverted sections run when property is false");
-    shouldCompileTo(string, {set: true}, " :: set", "inverted sections don't run when property is true");
+    shouldCompileTo(string, {}, 'not set :: ', "inverted sections run when property isn't present in context");
+    shouldCompileTo(string, {set: undefined}, 'not set :: ', 'inverted sections run when property is undefined');
+    shouldCompileTo(string, {set: false}, 'not set :: ', 'inverted sections run when property is false');
+    shouldCompileTo(string, {set: true}, ' :: set', "inverted sections don't run when property is true");
   });
 
-  it("GH-158: Using array index twice, breaks the template", function() {
-    var string = "{{arr.[0]}}, {{arr.[1]}}";
-    var data = { "arr": [1,2] };
+  it('GH-158: Using array index twice, breaks the template', function() {
+    var string = '{{arr.[0]}}, {{arr.[1]}}';
+    var data = { 'arr': [1, 2] };
 
-    shouldCompileTo(string, data, "1, 2", "it works as expected");
+    shouldCompileTo(string, data, '1, 2', 'it works as expected');
   });
 
   it("bug reported by @fat where lambdas weren't being properly resolved", function() {
@@ -39,12 +47,12 @@ describe('Regressions', function() {
         + '{{/hasThings}}';
     var data = {
       thing: function() {
-        return "blah";
+        return 'blah';
       },
       things: [
-        {className: "one", word: "@fat"},
-        {className: "two", word: "@dhg"},
-        {className: "three", word:"@sayrer"}
+        {className: 'one', word: '@fat'},
+        {className: 'two', word: '@dhg'},
+        {className: 'three', word: '@sayrer'}
       ],
       hasThings: function() {
         return true;
@@ -63,14 +71,14 @@ describe('Regressions', function() {
 
   it('GH-408: Multiple loops fail', function() {
     var context = [
-      { name: "John Doe", location: { city: "Chicago" } },
-      { name: "Jane Doe", location: { city: "New York"} }
+      { name: 'John Doe', location: { city: 'Chicago' } },
+      { name: 'Jane Doe', location: { city: 'New York'} }
     ];
 
     var template = CompilerContext.compile('{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}');
 
     var result = template(context);
-    equals(result, "John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe", 'It should output multiple times');
+    equals(result, 'John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe', 'It should output multiple times');
   });
 
   it('GS-428: Nested if else rendering', function() {
@@ -95,11 +103,13 @@ describe('Regressions', function() {
   });
 
   it('GH-534: Object prototype aliases', function() {
+    /*eslint-disable no-extend-native */
     Object.prototype[0xD834] = true;
 
     shouldCompileTo('{{foo}}', { foo: 'bar' }, 'bar');
 
     delete Object.prototype[0xD834];
+    /*eslint-enable no-extend-native */
   });
 
   it('GH-437: Matching escaping', function() {
@@ -111,23 +121,23 @@ describe('Regressions', function() {
     }, Error);
   });
 
-  it("GH-676: Using array in escaping mustache fails", function() {
-    var string = "{{arr}}";
-    var data = { "arr": [1,2] };
+  it('GH-676: Using array in escaping mustache fails', function() {
+    var string = '{{arr}}';
+    var data = { 'arr': [1, 2] };
 
-    shouldCompileTo(string, data, data.arr.toString(), "it works as expected");
+    shouldCompileTo(string, data, data.arr.toString(), 'it works as expected');
   });
 
-  it("Mustache man page", function() {
-    var string = "Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}";
+  it('Mustache man page', function() {
+    var string = 'Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}';
     var data = {
-      "name": "Chris",
-      "value": 10000,
-      "taxed_value": 10000 - (10000 * 0.4),
-      "in_ca": true
+      'name': 'Chris',
+      'value': 10000,
+      'taxed_value': 10000 - (10000 * 0.4),
+      'in_ca': true
     };
 
-    shouldCompileTo(string, data, "Hello Chris. You have just won $10000! Well, $6000, after taxes.", "the hello world mustache example works");
+    shouldCompileTo(string, data, 'Hello Chris. You have just won $10000! Well, $6000, after taxes.', 'the hello world mustache example works');
   });
 
   it('GH-731: zero context rendering', function() {
diff --git a/spec/require.js b/spec/require.js
index 11b7a0c93..6c0b5ae46 100644
--- a/spec/require.js
+++ b/spec/require.js
@@ -1,21 +1,21 @@
-if (typeof(require) !== 'undefined' && require.extensions[".handlebars"]) {
+if (typeof require !== 'undefined' && require.extensions['.handlebars']) {
   describe('Require', function() {
     it('Load .handlebars files with require()', function() {
-      var template = require("./artifacts/example_1");
-      equal(template, require("./artifacts/example_1.handlebars"));
+      var template = require('./artifacts/example_1');
+      equal(template, require('./artifacts/example_1.handlebars'));
 
       var expected = 'foo\n';
-      var result = template({foo: "foo"});
+      var result = template({foo: 'foo'});
 
       equal(result, expected);
     });
 
     it('Load .hbs files with require()', function() {
-      var template = require("./artifacts/example_2");
-      equal(template, require("./artifacts/example_2.hbs"));
+      var template = require('./artifacts/example_2');
+      equal(template, require('./artifacts/example_2.hbs'));
 
       var expected = 'Hello, World!\n';
-      var result = template({name: "World"});
+      var result = template({name: 'World'});
 
       equal(result, expected);
     });
diff --git a/spec/runtime.js b/spec/runtime.js
index ce8b14c56..502a8436b 100644
--- a/spec/runtime.js
+++ b/spec/runtime.js
@@ -1,5 +1,3 @@
-/*globals Handlebars, shouldThrow */
-
 describe('runtime', function() {
   describe('#template', function() {
     it('should throw on invalid templates', function() {
diff --git a/spec/source-map.js b/spec/source-map.js
index 8037b88c2..54e5e4d91 100644
--- a/spec/source-map.js
+++ b/spec/source-map.js
@@ -1,8 +1,7 @@
-/*global CompilerContext, Handlebars */
 try {
   if (typeof define !== 'function' || !define.amd) {
     var SourceMap = require('source-map'),
-          SourceMapConsumer = SourceMap.SourceMapConsumer;
+         SourceMapConsumer = SourceMap.SourceMapConsumer;
   }
 } catch (err) {
   /* NOP for in browser */
@@ -20,13 +19,13 @@ describe('source-map', function() {
     equal(!!template.map, !CompilerContext.browser);
   });
   it('should map source properly', function() {
-    var source = '  b{{hello}}  \n  {{bar}}a {{#block arg hash=(subex 1 subval)}}{{/block}}',
-        template = Handlebars.precompile(source, {destName: 'dest.js', srcName: 'src.hbs'});
+    var templateSource = '  b{{hello}}  \n  {{bar}}a {{#block arg hash=(subex 1 subval)}}{{/block}}',
+        template = Handlebars.precompile(templateSource, {destName: 'dest.js', srcName: 'src.hbs'});
 
     if (template.map) {
       var consumer = new SourceMapConsumer(template.map),
           lines = template.code.split('\n'),
-          srcLines = source.split('\n'),
+          srcLines = templateSource.split('\n'),
 
           generated = grepLine('"  b"', lines),
           source = grepLine('  b', srcLines);
@@ -43,7 +42,7 @@ function grepLine(token, lines) {
     var column = lines[i].indexOf(token);
     if (column >= 0) {
       return {
-        line: i+1,
+        line: i + 1,
         column: column
       };
     }
diff --git a/spec/spec.js b/spec/spec.js
index 2dd2bd8f0..ae1ec3805 100644
--- a/spec/spec.js
+++ b/spec/spec.js
@@ -5,12 +5,11 @@ describe('spec', function() {
   }
 
   var _ = require('underscore'),
-      Handlebars = require('../lib'),
       fs = require('fs');
 
-  var specDir =__dirname + '/mustache/specs/';
+  var specDir = __dirname + '/mustache/specs/';
   var specs = _.filter(fs.readdirSync(specDir), function(name) {
-    return /.*\.json$/.test(name);
+    return (/.*\.json$/).test(name);
   });
 
   _.each(specs, function(name) {
@@ -26,8 +25,8 @@ describe('spec', function() {
           // We nest the entire response from partials, not just the literals
           || (name === 'partials.json' && test.name === 'Standalone Indentation')
 
-          || /\{\{\=/.test(test.template)
-          || _.any(test.partials, function(partial) { return /\{\{\=/.test(partial); })) {
+          || (/\{\{\=/).test(test.template)
+          || _.any(test.partials, function(partial) { return (/\{\{\=/).test(partial); })) {
         it.skip(name + ' - ' + test.name);
         return;
       }
@@ -35,7 +34,9 @@ describe('spec', function() {
       var data = _.clone(test.data);
       if (data.lambda) {
         // Blergh
+        /*eslint-disable no-eval */
         data.lambda = eval('(' + data.lambda.js + ')');
+        /*eslint-enable no-eval */
       }
       it(name + ' - ' + test.name, function() {
         if (test.partials) {
diff --git a/spec/strict.js b/spec/strict.js
index f701866fe..2aef13442 100644
--- a/spec/strict.js
+++ b/spec/strict.js
@@ -1,4 +1,3 @@
-/*global CompilerContext, Handlebars, shouldThrow */
 var Exception = Handlebars.Exception;
 
 describe('strict', function() {
diff --git a/spec/string-params.js b/spec/string-params.js
index 4704a84f4..b76f291f7 100644
--- a/spec/string-params.js
+++ b/spec/string-params.js
@@ -1,44 +1,43 @@
-/*global CompilerContext */
 describe('string params mode', function() {
-  it("arguments to helpers can be retrieved from options hash in string form", function() {
+  it('arguments to helpers can be retrieved from options hash in string form', function() {
     var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {stringParams: true});
 
     var helpers = {
       wycats: function(passiveVoice, noun) {
-        return "HELP ME MY BOSS " + passiveVoice + ' ' + noun;
+        return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun;
       }
     };
 
     var result = template({}, {helpers: helpers});
 
-    equals(result, "HELP ME MY BOSS is.a slave.driver", "String parameters output");
+    equals(result, 'HELP ME MY BOSS is.a slave.driver', 'String parameters output');
   });
 
-  it("when using block form, arguments to helpers can be retrieved from options hash in string form", function() {
+  it('when using block form, arguments to helpers can be retrieved from options hash in string form', function() {
     var template = CompilerContext.compile('{{#wycats is.a slave.driver}}help :({{/wycats}}', {stringParams: true});
 
     var helpers = {
       wycats: function(passiveVoice, noun, options) {
-        return "HELP ME MY BOSS " + passiveVoice + ' ' +
+        return 'HELP ME MY BOSS ' + passiveVoice + ' ' +
                 noun + ': ' + options.fn(this);
       }
     };
 
     var result = template({}, {helpers: helpers});
 
-    equals(result, "HELP ME MY BOSS is.a slave.driver: help :(", "String parameters output");
+    equals(result, 'HELP ME MY BOSS is.a slave.driver: help :(', 'String parameters output');
   });
 
-  it("when inside a block in String mode, .. passes the appropriate context in the options hash", function() {
+  it('when inside a block in String mode, .. passes the appropriate context in the options hash', function() {
     var template = CompilerContext.compile('{{#with dale}}{{tomdale ../need dad.joke}}{{/with}}', {stringParams: true});
 
     var helpers = {
       tomdale: function(desire, noun, options) {
-        return "STOP ME FROM READING HACKER NEWS I " +
-                options.contexts[0][desire] + " " + noun;
+        return 'STOP ME FROM READING HACKER NEWS I ' +
+                options.contexts[0][desire] + ' ' + noun;
       },
 
-      "with": function(context, options) {
+      'with': function(context, options) {
         return options.fn(options.contexts[0][context]);
       }
     };
@@ -49,31 +48,31 @@ describe('string params mode', function() {
       need: 'need-a'
     }, {helpers: helpers});
 
-    equals(result, "STOP ME FROM READING HACKER NEWS I need-a dad.joke", "Proper context variable output");
+    equals(result, 'STOP ME FROM READING HACKER NEWS I need-a dad.joke', 'Proper context variable output');
   });
 
-  it("information about the types is passed along", function() {
-    var template = CompilerContext.compile('{{tomdale "need" dad.joke true false}}', { stringParams: true });
+  it('information about the types is passed along', function() {
+    var template = CompilerContext.compile("{{tomdale 'need' dad.joke true false}}", { stringParams: true });
 
     var helpers = {
       tomdale: function(desire, noun, trueBool, falseBool, options) {
-        equal(options.types[0], 'StringLiteral', "the string type is passed");
-        equal(options.types[1], 'PathExpression', "the expression type is passed");
-        equal(options.types[2], 'BooleanLiteral', "the expression type is passed");
-        equal(desire, "need", "the string form is passed for strings");
-        equal(noun, "dad.joke", "the string form is passed for expressions");
-        equal(trueBool, true, "raw booleans are passed through");
-        equal(falseBool, false, "raw booleans are passed through");
-        return "Helper called";
+        equal(options.types[0], 'StringLiteral', 'the string type is passed');
+        equal(options.types[1], 'PathExpression', 'the expression type is passed');
+        equal(options.types[2], 'BooleanLiteral', 'the expression type is passed');
+        equal(desire, 'need', 'the string form is passed for strings');
+        equal(noun, 'dad.joke', 'the string form is passed for expressions');
+        equal(trueBool, true, 'raw booleans are passed through');
+        equal(falseBool, false, 'raw booleans are passed through');
+        return 'Helper called';
       }
     };
 
     var result = template({}, { helpers: helpers });
-    equal(result, "Helper called");
+    equal(result, 'Helper called');
   });
 
-  it("hash parameters get type information", function() {
-    var template = CompilerContext.compile('{{tomdale he.says desire="need" noun=dad.joke bool=true}}', { stringParams: true });
+  it('hash parameters get type information', function() {
+    var template = CompilerContext.compile("{{tomdale he.says desire='need' noun=dad.joke bool=true}}", { stringParams: true });
 
     var helpers = {
       tomdale: function(exclamation, options) {
@@ -94,43 +93,43 @@ describe('string params mode', function() {
     equal(result, 'Helper called');
   });
 
-  it("hash parameters get context information", function() {
-    var template = CompilerContext.compile('{{#with dale}}{{tomdale he.says desire="need" noun=../dad/joke bool=true}}{{/with}}', { stringParams: true });
+  it('hash parameters get context information', function() {
+    var template = CompilerContext.compile("{{#with dale}}{{tomdale he.says desire='need' noun=../dad/joke bool=true}}{{/with}}", { stringParams: true });
 
     var context = {dale: {}};
 
     var helpers = {
       tomdale: function(exclamation, options) {
-        equal(exclamation, "he.says");
+        equal(exclamation, 'he.says');
         equal(options.types[0], 'PathExpression');
 
         equal(options.contexts.length, 1);
         equal(options.hashContexts.noun, context);
-        equal(options.hash.desire, "need");
-        equal(options.hash.noun, "dad.joke");
+        equal(options.hash.desire, 'need');
+        equal(options.hash.noun, 'dad.joke');
         equal(options.hash.bool, true);
-        return "Helper called";
+        return 'Helper called';
       },
-      "with": function(context, options) {
-        return options.fn(options.contexts[0][context]);
+      'with': function(withContext, options) {
+        return options.fn(options.contexts[0][withContext]);
       }
     };
 
     var result = template(context, { helpers: helpers });
-    equal(result, "Helper called");
+    equal(result, 'Helper called');
   });
 
-  it("when inside a block in String mode, .. passes the appropriate context in the options hash to a block helper", function() {
+  it('when inside a block in String mode, .. passes the appropriate context in the options hash to a block helper', function() {
     var template = CompilerContext.compile('{{#with dale}}{{#tomdale ../need dad.joke}}wot{{/tomdale}}{{/with}}', {stringParams: true});
 
     var helpers = {
       tomdale: function(desire, noun, options) {
-        return "STOP ME FROM READING HACKER NEWS I " +
-                options.contexts[0][desire] + " " + noun + " " +
+        return 'STOP ME FROM READING HACKER NEWS I ' +
+                options.contexts[0][desire] + ' ' + noun + ' ' +
                 options.fn(this);
       },
 
-      "with": function(context, options) {
+      'with': function(context, options) {
         return options.fn(options.contexts[0][context]);
       }
     };
@@ -141,23 +140,23 @@ describe('string params mode', function() {
       need: 'need-a'
     }, {helpers: helpers});
 
-    equals(result, "STOP ME FROM READING HACKER NEWS I need-a dad.joke wot", "Proper context variable output");
+    equals(result, 'STOP ME FROM READING HACKER NEWS I need-a dad.joke wot', 'Proper context variable output');
   });
 
-  it("with nested block ambiguous", function() {
+  it('with nested block ambiguous', function() {
     var template = CompilerContext.compile('{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}', {stringParams: true});
 
-    var helpers  = {
-      'with': function(options) {
-        return "WITH";
+    var helpers = {
+      'with': function() {
+        return 'WITH';
       },
       view: function() {
-        return "VIEW";
+        return 'VIEW';
       }
     };
 
     var result = template({}, {helpers: helpers});
-    equals(result, "WITH");
+    equals(result, 'WITH');
   });
 
   it('should handle DATA', function() {
diff --git a/spec/subexpressions.js b/spec/subexpressions.js
index 1fb877551..dad741e4a 100644
--- a/spec/subexpressions.js
+++ b/spec/subexpressions.js
@@ -1,134 +1,133 @@
-/*global CompilerContext, Handlebars, shouldCompileTo, shouldThrow */
 describe('subexpressions', function() {
-  it("arg-less helper", function() {
-    var string   = "{{foo (bar)}}!";
-    var context  = {};
-    var helpers  = {
+  it('arg-less helper', function() {
+    var string = '{{foo (bar)}}!';
+    var context = {};
+    var helpers = {
       foo: function(val) {
-        return val+val;
+        return val + val;
       },
       bar: function() {
-        return "LOL";
+        return 'LOL';
       }
     };
-    shouldCompileTo(string, [context, helpers], "LOLLOL!");
+    shouldCompileTo(string, [context, helpers], 'LOLLOL!');
   });
 
-  it("helper w args", function() {
-    var string   = '{{blog (equal a b)}}';
+  it('helper w args', function() {
+    var string = '{{blog (equal a b)}}';
 
-    var context  = { bar: "LOL" };
-    var helpers  = {
+    var context = { bar: 'LOL' };
+    var helpers = {
       blog: function(val) {
-        return "val is " + val;
+        return 'val is ' + val;
       },
       equal: function(x, y) {
         return x === y;
       }
     };
-    shouldCompileTo(string, [context, helpers], "val is true");
+    shouldCompileTo(string, [context, helpers], 'val is true');
   });
 
-  it("mixed paths and helpers", function() {
-    var string   = '{{blog baz.bat (equal a b) baz.bar}}';
+  it('mixed paths and helpers', function() {
+    var string = '{{blog baz.bat (equal a b) baz.bar}}';
 
-    var context  = { bar: "LOL", baz: {bat: 'foo!', bar: 'bar!'} };
-    var helpers  = {
+    var context = { bar: 'LOL', baz: {bat: 'foo!', bar: 'bar!'} };
+    var helpers = {
       blog: function(val, that, theOther) {
-        return "val is " + val + ', ' + that + ' and ' + theOther;
+        return 'val is ' + val + ', ' + that + ' and ' + theOther;
       },
       equal: function(x, y) {
         return x === y;
       }
     };
-    shouldCompileTo(string, [context, helpers], "val is foo!, true and bar!");
+    shouldCompileTo(string, [context, helpers], 'val is foo!, true and bar!');
   });
 
-  it("supports much nesting", function() {
-    var string   = '{{blog (equal (equal true true) true)}}';
+  it('supports much nesting', function() {
+    var string = '{{blog (equal (equal true true) true)}}';
 
-    var context  = { bar: "LOL" };
-    var helpers  = {
+    var context = { bar: 'LOL' };
+    var helpers = {
       blog: function(val) {
-        return "val is " + val;
+        return 'val is ' + val;
       },
       equal: function(x, y) {
         return x === y;
       }
     };
-    shouldCompileTo(string, [context, helpers], "val is true");
+    shouldCompileTo(string, [context, helpers], 'val is true');
   });
 
   it('GH-800 : Complex subexpressions', function() {
-    var context  = {a: 'a', b:'b', c:{c:'c'}, d:'d', e: {e: 'e'}};
-    var helpers  = {
+    var context = {a: 'a', b: 'b', c: {c: 'c'}, d: 'd', e: {e: 'e'}};
+    var helpers = {
       dash: function(a, b) {
-        return a + "-" + b;
+        return a + '-' + b;
       },
       concat: function(a, b) {
         return a + b;
       }
     };
 
-    shouldCompileTo('{{dash "abc" (concat a b)}}', [context, helpers], 'abc-ab');
+    shouldCompileTo("{{dash 'abc' (concat a b)}}", [context, helpers], 'abc-ab');
     shouldCompileTo('{{dash d (concat a b)}}', [context, helpers], 'd-ab');
     shouldCompileTo('{{dash c.c (concat a b)}}', [context, helpers], 'c-ab');
     shouldCompileTo('{{dash (concat a b) c.c}}', [context, helpers], 'ab-c');
     shouldCompileTo('{{dash (concat a e.e) c.c}}', [context, helpers], 'ae-c');
   });
 
-  it("provides each nested helper invocation its own options hash", function() {
+  it('provides each nested helper invocation its own options hash', function() {
     var string = '{{equal (equal true true) true}}';
 
     var lastOptions = null;
-    var helpers  = {
+    var helpers = {
       equal: function(x, y, options) {
         if (!options || options === lastOptions) {
-          throw new Error("options hash was reused");
+          throw new Error('options hash was reused');
         }
         lastOptions = options;
         return x === y;
       }
     };
-    shouldCompileTo(string, [{}, helpers], "true");
+    shouldCompileTo(string, [{}, helpers], 'true');
   });
 
-  it("with hashes", function() {
-    var string   = '{{blog (equal (equal true true) true fun="yes")}}';
+  it('with hashes', function() {
+    var string = "{{blog (equal (equal true true) true fun='yes')}}";
 
-    var context  = { bar: "LOL" };
-    var helpers  = {
+    var context = { bar: 'LOL' };
+    var helpers = {
       blog: function(val) {
-        return "val is " + val;
+        return 'val is ' + val;
       },
       equal: function(x, y) {
         return x === y;
       }
     };
-    shouldCompileTo(string, [context, helpers], "val is true");
+    shouldCompileTo(string, [context, helpers], 'val is true');
   });
 
-  it("as hashes", function() {
-    var string   = '{{blog fun=(equal (blog fun=1) "val is 1")}}';
+  it('as hashes', function() {
+    var string = "{{blog fun=(equal (blog fun=1) 'val is 1')}}";
 
-    var helpers  = {
+    var helpers = {
       blog: function(options) {
-        return "val is " + options.hash.fun;
+        return 'val is ' + options.hash.fun;
       },
       equal: function(x, y) {
         return x === y;
       }
     };
-    shouldCompileTo(string, [{}, helpers], "val is true");
+    shouldCompileTo(string, [{}, helpers], 'val is true');
   });
 
-  it("multiple subexpressions in a hash", function() {
+  it('multiple subexpressions in a hash', function() {
     var string = '{{input aria-label=(t "Name") placeholder=(t "Example User")}}';
 
     var helpers = {
       input: function(options) {
-        var hash        = options.hash;
-        var ariaLabel   = Handlebars.Utils.escapeExpression(hash['aria-label']);
+        var hash = options.hash;
+        var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
         var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder);
         return new Handlebars.SafeString('<input aria-label="' + ariaLabel + '" placeholder="' + placeholder + '" />');
       },
@@ -139,20 +138,20 @@ describe('subexpressions', function() {
     shouldCompileTo(string, [{}, helpers], '<input aria-label="Name" placeholder="Example User" />');
   });
 
-  it("multiple subexpressions in a hash with context", function() {
+  it('multiple subexpressions in a hash with context', function() {
     var string = '{{input aria-label=(t item.field) placeholder=(t item.placeholder)}}';
 
     var context = {
       item: {
-        field: "Name",
-        placeholder: "Example User"
-      } 
+        field: 'Name',
+        placeholder: 'Example User'
+      }
     };
 
     var helpers = {
       input: function(options) {
-        var hash        = options.hash;
-        var ariaLabel   = Handlebars.Utils.escapeExpression(hash['aria-label']);
+        var hash = options.hash;
+        var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
         var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder);
         return new Handlebars.SafeString('<input aria-label="' + ariaLabel + '" placeholder="' + placeholder + '" />');
       },
@@ -161,23 +160,23 @@ describe('subexpressions', function() {
       }
     };
     shouldCompileTo(string, [context, helpers], '<input aria-label="Name" placeholder="Example User" />');
-  });  
+  });
 
-  it("in string params mode,", function() {
+  it('in string params mode,', function() {
     var template = CompilerContext.compile('{{snog (blorg foo x=y) yeah a=b}}', {stringParams: true});
 
     var helpers = {
       snog: function(a, b, options) {
         equals(a, 'foo');
-        equals(options.types.length, 2, "string params for outer helper processed correctly");
-        equals(options.types[0], 'SubExpression', "string params for outer helper processed correctly");
-        equals(options.types[1], 'PathExpression', "string params for outer helper processed correctly");
+        equals(options.types.length, 2, 'string params for outer helper processed correctly');
+        equals(options.types[0], 'SubExpression', 'string params for outer helper processed correctly');
+        equals(options.types[1], 'PathExpression', 'string params for outer helper processed correctly');
         return a + b;
       },
 
       blorg: function(a, options) {
-        equals(options.types.length, 1, "string params for inner helper processed correctly");
-        equals(options.types[0], 'PathExpression', "string params for inner helper processed correctly");
+        equals(options.types.length, 1, 'string params for inner helper processed correctly');
+        equals(options.types[0], 'PathExpression', 'string params for inner helper processed correctly');
         return a;
       }
     };
@@ -187,54 +186,53 @@ describe('subexpressions', function() {
       yeah: {}
     }, {helpers: helpers});
 
-    equals(result, "fooyeah");
+    equals(result, 'fooyeah');
   });
 
-  it("as hashes in string params mode", function() {
-
+  it('as hashes in string params mode', function() {
     var template = CompilerContext.compile('{{blog fun=(bork)}}', {stringParams: true});
 
-    var helpers  = {
+    var helpers = {
       blog: function(options) {
         equals(options.hashTypes.fun, 'SubExpression');
-        return "val is " + options.hash.fun;
+        return 'val is ' + options.hash.fun;
       },
       bork: function() {
-        return "BORK";
+        return 'BORK';
       }
     };
 
     var result = template({}, {helpers: helpers});
-    equals(result, "val is BORK");
+    equals(result, 'val is BORK');
   });
 
-  it("subexpression functions on the context", function() {
-    var string   = "{{foo (bar)}}!";
-    var context  = {
+  it('subexpression functions on the context', function() {
+    var string = '{{foo (bar)}}!';
+    var context = {
       bar: function() {
-        return "LOL";
+        return 'LOL';
       }
     };
-    var helpers  = {
+    var helpers = {
       foo: function(val) {
-        return val+val;
+        return val + val;
       }
     };
-    shouldCompileTo(string, [context, helpers], "LOLLOL!");
+    shouldCompileTo(string, [context, helpers], 'LOLLOL!');
   });
 
   it("subexpressions can't just be property lookups", function() {
-    var string   = "{{foo (bar)}}!";
-    var context  = {
-      bar: "LOL"
+    var string = '{{foo (bar)}}!';
+    var context = {
+      bar: 'LOL'
     };
-    var helpers  = {
+    var helpers = {
       foo: function(val) {
-        return val+val;
+        return val + val;
       }
     };
     shouldThrow(function() {
-      shouldCompileTo(string, [context, helpers], "LOLLOL!");
+      shouldCompileTo(string, [context, helpers], 'LOLLOL!');
     });
   });
 });
diff --git a/spec/tokenizer.js b/spec/tokenizer.js
index 26a1c3b51..ad71dc9b2 100644
--- a/spec/tokenizer.js
+++ b/spec/tokenizer.js
@@ -1,4 +1,3 @@
-/*global Handlebars */
 function shouldMatchTokens(result, tokens) {
   for (var index = 0; index < result.length; index++) {
     equals(result[index].name, tokens[index]);
@@ -22,7 +21,7 @@ describe('Tokenizer', function() {
     var out = [],
         token;
 
-    while (token = lexer.lex()) {
+    while ((token = lexer.lex())) {
       var result = parser.terminals_[token] || token;
       if (!result || result === 'EOF' || result === 'INVALID') {
         break;
@@ -34,292 +33,292 @@ describe('Tokenizer', function() {
   }
 
   it('tokenizes a simple mustache as "OPEN ID CLOSE"', function() {
-    var result = tokenize("{{foo}}");
+    var result = tokenize('{{foo}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "ID", "foo");
+    shouldBeToken(result[1], 'ID', 'foo');
   });
 
   it('supports unescaping with &', function() {
-    var result = tokenize("{{&bar}}");
+    var result = tokenize('{{&bar}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
 
-    shouldBeToken(result[0], "OPEN", "{{&");
-    shouldBeToken(result[1], "ID", "bar");
+    shouldBeToken(result[0], 'OPEN', '{{&');
+    shouldBeToken(result[1], 'ID', 'bar');
   });
 
   it('supports unescaping with {{{', function() {
-    var result = tokenize("{{{bar}}}");
+    var result = tokenize('{{{bar}}}');
     shouldMatchTokens(result, ['OPEN_UNESCAPED', 'ID', 'CLOSE_UNESCAPED']);
 
-    shouldBeToken(result[1], "ID", "bar");
+    shouldBeToken(result[1], 'ID', 'bar');
   });
 
   it('supports escaping delimiters', function() {
-    var result = tokenize("{{foo}} \\{{bar}} {{baz}}");
+    var result = tokenize('{{foo}} \\{{bar}} {{baz}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
 
-    shouldBeToken(result[3], "CONTENT", " ");
-    shouldBeToken(result[4], "CONTENT", "{{bar}} ");
+    shouldBeToken(result[3], 'CONTENT', ' ');
+    shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
   });
 
   it('supports escaping multiple delimiters', function() {
-    var result = tokenize("{{foo}} \\{{bar}} \\{{baz}}");
+    var result = tokenize('{{foo}} \\{{bar}} \\{{baz}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT']);
 
-    shouldBeToken(result[3], "CONTENT", " ");
-    shouldBeToken(result[4], "CONTENT", "{{bar}} ");
-    shouldBeToken(result[5], "CONTENT", "{{baz}}");
+    shouldBeToken(result[3], 'CONTENT', ' ');
+    shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
+    shouldBeToken(result[5], 'CONTENT', '{{baz}}');
   });
 
   it('supports escaping a triple stash', function() {
-    var result = tokenize("{{foo}} \\{{{bar}}} {{baz}}");
+    var result = tokenize('{{foo}} \\{{{bar}}} {{baz}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
 
-    shouldBeToken(result[4], "CONTENT", "{{{bar}}} ");
+    shouldBeToken(result[4], 'CONTENT', '{{{bar}}} ');
   });
 
   it('supports escaping escape character', function() {
-    var result = tokenize("{{foo}} \\\\{{bar}} {{baz}}");
+    var result = tokenize('{{foo}} \\\\{{bar}} {{baz}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
 
-    shouldBeToken(result[3], "CONTENT", " \\");
-    shouldBeToken(result[5], "ID", "bar");
+    shouldBeToken(result[3], 'CONTENT', ' \\');
+    shouldBeToken(result[5], 'ID', 'bar');
   });
 
   it('supports escaping multiple escape characters', function() {
-    var result = tokenize("{{foo}} \\\\{{bar}} \\\\{{baz}}");
+    var result = tokenize('{{foo}} \\\\{{bar}} \\\\{{baz}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
 
-    shouldBeToken(result[3], "CONTENT", " \\");
-    shouldBeToken(result[5], "ID", "bar");
-    shouldBeToken(result[7], "CONTENT", " \\");
-    shouldBeToken(result[9], "ID", "baz");
+    shouldBeToken(result[3], 'CONTENT', ' \\');
+    shouldBeToken(result[5], 'ID', 'bar');
+    shouldBeToken(result[7], 'CONTENT', ' \\');
+    shouldBeToken(result[9], 'ID', 'baz');
   });
 
   it('supports escaped mustaches after escaped escape characters', function() {
-    var result = tokenize("{{foo}} \\\\{{bar}} \\{{baz}}");
+    var result = tokenize('{{foo}} \\\\{{bar}} \\{{baz}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT']);
 
-    shouldBeToken(result[3], "CONTENT", " \\");
-    shouldBeToken(result[4], "OPEN", "{{");
-    shouldBeToken(result[5], "ID", "bar");
-    shouldBeToken(result[7], "CONTENT", " ");
-    shouldBeToken(result[8], "CONTENT", "{{baz}}");
+    shouldBeToken(result[3], 'CONTENT', ' \\');
+    shouldBeToken(result[4], 'OPEN', '{{');
+    shouldBeToken(result[5], 'ID', 'bar');
+    shouldBeToken(result[7], 'CONTENT', ' ');
+    shouldBeToken(result[8], 'CONTENT', '{{baz}}');
   });
 
   it('supports escaped escape characters after escaped mustaches', function() {
-    var result = tokenize("{{foo}} \\{{bar}} \\\\{{baz}}");
+    var result = tokenize('{{foo}} \\{{bar}} \\\\{{baz}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
 
-    shouldBeToken(result[4], "CONTENT", "{{bar}} ");
-    shouldBeToken(result[5], "CONTENT", "\\");
-    shouldBeToken(result[6], "OPEN", "{{");
-    shouldBeToken(result[7], "ID", "baz");
+    shouldBeToken(result[4], 'CONTENT', '{{bar}} ');
+    shouldBeToken(result[5], 'CONTENT', '\\');
+    shouldBeToken(result[6], 'OPEN', '{{');
+    shouldBeToken(result[7], 'ID', 'baz');
   });
 
   it('supports escaped escape character on a triple stash', function() {
-    var result = tokenize("{{foo}} \\\\{{{bar}}} {{baz}}");
+    var result = tokenize('{{foo}} \\\\{{{bar}}} {{baz}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN_UNESCAPED', 'ID', 'CLOSE_UNESCAPED', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
 
-    shouldBeToken(result[3], "CONTENT", " \\");
-    shouldBeToken(result[5], "ID", "bar");
+    shouldBeToken(result[3], 'CONTENT', ' \\');
+    shouldBeToken(result[5], 'ID', 'bar');
   });
 
   it('tokenizes a simple path', function() {
-    var result = tokenize("{{foo/bar}}");
+    var result = tokenize('{{foo/bar}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
   });
 
   it('allows dot notation', function() {
-    var result = tokenize("{{foo.bar}}");
+    var result = tokenize('{{foo.bar}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
 
-    shouldMatchTokens(tokenize("{{foo.bar.baz}}"), ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
+    shouldMatchTokens(tokenize('{{foo.bar.baz}}'), ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
   });
 
   it('allows path literals with []', function() {
-    var result = tokenize("{{foo.[bar]}}");
+    var result = tokenize('{{foo.[bar]}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
   });
 
   it('allows multiple path literals on a line with []', function() {
-    var result = tokenize("{{foo.[bar]}}{{foo.[baz]}}");
+    var result = tokenize('{{foo.[bar]}}{{foo.[baz]}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE', 'OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
   });
 
   it('tokenizes {{.}} as OPEN ID CLOSE', function() {
-    var result = tokenize("{{.}}");
+    var result = tokenize('{{.}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
   });
 
   it('tokenizes a path as "OPEN (ID SEP)* ID CLOSE"', function() {
-    var result = tokenize("{{../foo/bar}}");
+    var result = tokenize('{{../foo/bar}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "ID", "..");
+    shouldBeToken(result[1], 'ID', '..');
   });
 
   it('tokenizes a path with .. as a parent path', function() {
-    var result = tokenize("{{../foo.bar}}");
+    var result = tokenize('{{../foo.bar}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "ID", "..");
+    shouldBeToken(result[1], 'ID', '..');
   });
 
   it('tokenizes a path with this/foo as OPEN ID SEP ID CLOSE', function() {
-    var result = tokenize("{{this/foo}}");
+    var result = tokenize('{{this/foo}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "ID", "this");
-    shouldBeToken(result[3], "ID", "foo");
+    shouldBeToken(result[1], 'ID', 'this');
+    shouldBeToken(result[3], 'ID', 'foo');
   });
 
   it('tokenizes a simple mustache with spaces as "OPEN ID CLOSE"', function() {
-    var result = tokenize("{{  foo  }}");
+    var result = tokenize('{{  foo  }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "ID", "foo");
+    shouldBeToken(result[1], 'ID', 'foo');
   });
 
   it('tokenizes a simple mustache with line breaks as "OPEN ID ID CLOSE"', function() {
-    var result = tokenize("{{  foo  \n   bar }}");
+    var result = tokenize('{{  foo  \n   bar }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "ID", "foo");
+    shouldBeToken(result[1], 'ID', 'foo');
   });
 
   it('tokenizes raw content as "CONTENT"', function() {
-    var result = tokenize("foo {{ bar }} baz");
+    var result = tokenize('foo {{ bar }} baz');
     shouldMatchTokens(result, ['CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT']);
-    shouldBeToken(result[0], "CONTENT", "foo ");
-    shouldBeToken(result[4], "CONTENT", " baz");
+    shouldBeToken(result[0], 'CONTENT', 'foo ');
+    shouldBeToken(result[4], 'CONTENT', ' baz');
   });
 
   it('tokenizes a partial as "OPEN_PARTIAL ID CLOSE"', function() {
-    var result = tokenize("{{> foo}}");
+    var result = tokenize('{{> foo}}');
     shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
   });
 
   it('tokenizes a partial with context as "OPEN_PARTIAL ID ID CLOSE"', function() {
-    var result = tokenize("{{> foo bar }}");
+    var result = tokenize('{{> foo bar }}');
     shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'ID', 'CLOSE']);
   });
 
   it('tokenizes a partial without spaces as "OPEN_PARTIAL ID CLOSE"', function() {
-    var result = tokenize("{{>foo}}");
+    var result = tokenize('{{>foo}}');
     shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
   });
 
   it('tokenizes a partial space at the }); as "OPEN_PARTIAL ID CLOSE"', function() {
-    var result = tokenize("{{>foo  }}");
+    var result = tokenize('{{>foo  }}');
     shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']);
   });
 
   it('tokenizes a partial space at the }); as "OPEN_PARTIAL ID CLOSE"', function() {
-    var result = tokenize("{{>foo/bar.baz  }}");
+    var result = tokenize('{{>foo/bar.baz  }}');
     shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']);
   });
 
   it('tokenizes a comment as "COMMENT"', function() {
-    var result = tokenize("foo {{! this is a comment }} bar {{ baz }}");
+    var result = tokenize('foo {{! this is a comment }} bar {{ baz }}');
     shouldMatchTokens(result, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "COMMENT", "{{! this is a comment }}");
+    shouldBeToken(result[1], 'COMMENT', '{{! this is a comment }}');
   });
 
   it('tokenizes a block comment as "COMMENT"', function() {
-    var result = tokenize("foo {{!-- this is a {{comment}} --}} bar {{ baz }}");
+    var result = tokenize('foo {{!-- this is a {{comment}} --}} bar {{ baz }}');
     shouldMatchTokens(result, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "COMMENT", "{{!-- this is a {{comment}} --}}");
+    shouldBeToken(result[1], 'COMMENT', '{{!-- this is a {{comment}} --}}');
   });
 
   it('tokenizes a block comment with whitespace as "COMMENT"', function() {
-    var result = tokenize("foo {{!-- this is a\n{{comment}}\n--}} bar {{ baz }}");
+    var result = tokenize('foo {{!-- this is a\n{{comment}}\n--}} bar {{ baz }}');
     shouldMatchTokens(result, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "COMMENT", "{{!-- this is a\n{{comment}}\n--}}");
+    shouldBeToken(result[1], 'COMMENT', '{{!-- this is a\n{{comment}}\n--}}');
   });
 
   it('tokenizes open and closing blocks as OPEN_BLOCK, ID, CLOSE ..., OPEN_ENDBLOCK ID CLOSE', function() {
-    var result = tokenize("{{#foo}}content{{/foo}}");
+    var result = tokenize('{{#foo}}content{{/foo}}');
     shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'CLOSE', 'CONTENT', 'OPEN_ENDBLOCK', 'ID', 'CLOSE']);
   });
 
   it('tokenizes inverse sections as "INVERSE"', function() {
-    shouldMatchTokens(tokenize("{{^}}"), ['INVERSE']);
-    shouldMatchTokens(tokenize("{{else}}"), ['INVERSE']);
-    shouldMatchTokens(tokenize("{{ else }}"), ['INVERSE']);
+    shouldMatchTokens(tokenize('{{^}}'), ['INVERSE']);
+    shouldMatchTokens(tokenize('{{else}}'), ['INVERSE']);
+    shouldMatchTokens(tokenize('{{ else }}'), ['INVERSE']);
   });
 
   it('tokenizes inverse sections with ID as "OPEN_INVERSE ID CLOSE"', function() {
-    var result = tokenize("{{^foo}}");
+    var result = tokenize('{{^foo}}');
     shouldMatchTokens(result, ['OPEN_INVERSE', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "ID", "foo");
+    shouldBeToken(result[1], 'ID', 'foo');
   });
 
   it('tokenizes inverse sections with ID and spaces as "OPEN_INVERSE ID CLOSE"', function() {
-    var result = tokenize("{{^ foo  }}");
+    var result = tokenize('{{^ foo  }}');
     shouldMatchTokens(result, ['OPEN_INVERSE', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "ID", "foo");
+    shouldBeToken(result[1], 'ID', 'foo');
   });
 
   it('tokenizes mustaches with params as "OPEN ID ID ID CLOSE"', function() {
-    var result = tokenize("{{ foo bar baz }}");
+    var result = tokenize('{{ foo bar baz }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'CLOSE']);
-    shouldBeToken(result[1], "ID", "foo");
-    shouldBeToken(result[2], "ID", "bar");
-    shouldBeToken(result[3], "ID", "baz");
+    shouldBeToken(result[1], 'ID', 'foo');
+    shouldBeToken(result[2], 'ID', 'bar');
+    shouldBeToken(result[3], 'ID', 'baz');
   });
 
   it('tokenizes mustaches with String params as "OPEN ID ID STRING CLOSE"', function() {
-    var result = tokenize("{{ foo bar \"baz\" }}");
+    var result = tokenize('{{ foo bar \'baz\' }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']);
-    shouldBeToken(result[3], "STRING", "baz");
+    shouldBeToken(result[3], 'STRING', 'baz');
   });
 
   it('tokenizes mustaches with String params using single quotes as "OPEN ID ID STRING CLOSE"', function() {
     var result = tokenize("{{ foo bar \'baz\' }}");
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']);
-    shouldBeToken(result[3], "STRING", "baz");
+    shouldBeToken(result[3], 'STRING', 'baz');
   });
 
   it('tokenizes String params with spaces inside as "STRING"', function() {
-    var result = tokenize("{{ foo bar \"baz bat\" }}");
+    var result = tokenize('{{ foo bar "baz bat" }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']);
-    shouldBeToken(result[3], "STRING", "baz bat");
+    shouldBeToken(result[3], 'STRING', 'baz bat');
   });
 
   it('tokenizes String params with escapes quotes as STRING', function() {
     var result = tokenize('{{ foo "bar\\"baz" }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'STRING', 'CLOSE']);
-    shouldBeToken(result[2], "STRING", 'bar"baz');
+    shouldBeToken(result[2], 'STRING', 'bar"baz');
   });
 
   it('tokenizes String params using single quotes with escapes quotes as STRING', function() {
     var result = tokenize("{{ foo 'bar\\'baz' }}");
     shouldMatchTokens(result, ['OPEN', 'ID', 'STRING', 'CLOSE']);
-    shouldBeToken(result[2], "STRING", "bar'baz");
+    shouldBeToken(result[2], 'STRING', "bar'baz");
   });
 
   it('tokenizes numbers', function() {
     var result = tokenize('{{ foo 1 }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
-    shouldBeToken(result[2], "NUMBER", "1");
+    shouldBeToken(result[2], 'NUMBER', '1');
 
     result = tokenize('{{ foo 1.1 }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
-    shouldBeToken(result[2], "NUMBER", "1.1");
+    shouldBeToken(result[2], 'NUMBER', '1.1');
 
     result = tokenize('{{ foo -1 }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
-    shouldBeToken(result[2], "NUMBER", "-1");
+    shouldBeToken(result[2], 'NUMBER', '-1');
 
     result = tokenize('{{ foo -1.1 }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']);
-    shouldBeToken(result[2], "NUMBER", "-1.1");
+    shouldBeToken(result[2], 'NUMBER', '-1.1');
   });
 
   it('tokenizes booleans', function() {
     var result = tokenize('{{ foo true }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'BOOLEAN', 'CLOSE']);
-    shouldBeToken(result[2], "BOOLEAN", "true");
+    shouldBeToken(result[2], 'BOOLEAN', 'true');
 
     result = tokenize('{{ foo false }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'BOOLEAN', 'CLOSE']);
-    shouldBeToken(result[2], "BOOLEAN", "false");
+    shouldBeToken(result[2], 'BOOLEAN', 'false');
   });
 
   it('tokenizes undefined and null', function() {
@@ -330,77 +329,77 @@ describe('Tokenizer', function() {
   });
 
   it('tokenizes hash arguments', function() {
-    var result = tokenize("{{ foo bar=baz }}");
+    var result = tokenize('{{ foo bar=baz }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
 
-    result = tokenize("{{ foo bar baz=bat }}");
+    result = tokenize('{{ foo bar baz=bat }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
 
-    result = tokenize("{{ foo bar baz=1 }}");
+    result = tokenize('{{ foo bar baz=1 }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'NUMBER', 'CLOSE']);
 
-    result = tokenize("{{ foo bar baz=true }}");
+    result = tokenize('{{ foo bar baz=true }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'BOOLEAN', 'CLOSE']);
 
-    result = tokenize("{{ foo bar baz=false }}");
+    result = tokenize('{{ foo bar baz=false }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'BOOLEAN', 'CLOSE']);
 
-    result = tokenize("{{ foo bar\n  baz=bat }}");
+    result = tokenize('{{ foo bar\n  baz=bat }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
 
-    result = tokenize("{{ foo bar baz=\"bat\" }}");
+    result = tokenize('{{ foo bar baz=\"bat\" }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'STRING', 'CLOSE']);
 
-    result = tokenize("{{ foo bar baz=\"bat\" bam=wot }}");
+    result = tokenize('{{ foo bar baz=\"bat\" bam=wot }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'STRING', 'ID', 'EQUALS', 'ID', 'CLOSE']);
 
-    result = tokenize("{{foo omg bar=baz bat=\"bam\"}}");
+    result = tokenize('{{foo omg bar=baz bat=\"bam\"}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'ID', 'EQUALS', 'STRING', 'CLOSE']);
-    shouldBeToken(result[2], "ID", "omg");
+    shouldBeToken(result[2], 'ID', 'omg');
   });
 
   it('tokenizes special @ identifiers', function() {
-    var result = tokenize("{{ @foo }}");
+    var result = tokenize('{{ @foo }}');
     shouldMatchTokens(result, ['OPEN', 'DATA', 'ID', 'CLOSE']);
-    shouldBeToken(result[2], "ID", "foo");
+    shouldBeToken(result[2], 'ID', 'foo');
 
-    result = tokenize("{{ foo @bar }}");
+    result = tokenize('{{ foo @bar }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'DATA', 'ID', 'CLOSE']);
-    shouldBeToken(result[3], "ID", "bar");
+    shouldBeToken(result[3], 'ID', 'bar');
 
-    result = tokenize("{{ foo bar=@baz }}");
+    result = tokenize('{{ foo bar=@baz }}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'DATA', 'ID', 'CLOSE']);
-    shouldBeToken(result[5], "ID", "baz");
+    shouldBeToken(result[5], 'ID', 'baz');
   });
 
   it('does not time out in a mustache with a single } followed by EOF', function() {
-    shouldMatchTokens(tokenize("{{foo}"), ['OPEN', 'ID']);
+    shouldMatchTokens(tokenize('{{foo}'), ['OPEN', 'ID']);
   });
 
   it('does not time out in a mustache when invalid ID characters are used', function() {
-    shouldMatchTokens(tokenize("{{foo & }}"), ['OPEN', 'ID']);
+    shouldMatchTokens(tokenize('{{foo & }}'), ['OPEN', 'ID']);
   });
 
   it('tokenizes subexpressions', function() {
-    var result = tokenize("{{foo (bar)}}");
+    var result = tokenize('{{foo (bar)}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'CLOSE_SEXPR', 'CLOSE']);
-    shouldBeToken(result[1], "ID", "foo");
-    shouldBeToken(result[3], "ID", "bar");
+    shouldBeToken(result[1], 'ID', 'foo');
+    shouldBeToken(result[3], 'ID', 'bar');
 
-    result = tokenize("{{foo (a-x b-y)}}");
+    result = tokenize('{{foo (a-x b-y)}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'ID', 'CLOSE_SEXPR', 'CLOSE']);
-    shouldBeToken(result[1], "ID", "foo");
-    shouldBeToken(result[3], "ID", "a-x");
-    shouldBeToken(result[4], "ID", "b-y");
+    shouldBeToken(result[1], 'ID', 'foo');
+    shouldBeToken(result[3], 'ID', 'a-x');
+    shouldBeToken(result[4], 'ID', 'b-y');
   });
 
   it('tokenizes nested subexpressions', function() {
-    var result = tokenize("{{foo (bar (lol rofl)) (baz)}}");
+    var result = tokenize('{{foo (bar (lol rofl)) (baz)}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'OPEN_SEXPR', 'ID', 'ID', 'CLOSE_SEXPR', 'CLOSE_SEXPR', 'OPEN_SEXPR', 'ID', 'CLOSE_SEXPR', 'CLOSE']);
-    shouldBeToken(result[3],  "ID", "bar");
-    shouldBeToken(result[5],  "ID", "lol");
-    shouldBeToken(result[6],  "ID", "rofl");
-    shouldBeToken(result[10], "ID", "baz");
+    shouldBeToken(result[3], 'ID', 'bar');
+    shouldBeToken(result[5], 'ID', 'lol');
+    shouldBeToken(result[6], 'ID', 'rofl');
+    shouldBeToken(result[10], 'ID', 'baz');
   });
 
   it('tokenizes nested subexpressions: literals', function() {
@@ -409,19 +408,19 @@ describe('Tokenizer', function() {
   });
 
   it('tokenizes block params', function() {
-    var result = tokenize("{{#foo as |bar|}}");
+    var result = tokenize('{{#foo as |bar|}}');
     shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
 
-    result = tokenize("{{#foo as |bar baz|}}");
+    result = tokenize('{{#foo as |bar baz|}}');
     shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
 
-    result = tokenize("{{#foo as | bar baz |}}");
+    result = tokenize('{{#foo as | bar baz |}}');
     shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
 
-    result = tokenize("{{#foo as as | bar baz |}}");
+    result = tokenize('{{#foo as as | bar baz |}}');
     shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
 
-    result = tokenize("{{else foo as |bar baz|}}");
+    result = tokenize('{{else foo as |bar baz|}}');
     shouldMatchTokens(result, ['OPEN_INVERSE_CHAIN', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
   });
 });
diff --git a/spec/track-ids.js b/spec/track-ids.js
index f337fbe11..7a8b59ee4 100644
--- a/spec/track-ids.js
+++ b/spec/track-ids.js
@@ -1,4 +1,3 @@
-/*global CompilerContext */
 describe('track ids', function() {
   var context;
   beforeEach(function() {
@@ -27,7 +26,7 @@ describe('track ids', function() {
         equal(options.ids[0], 'is.a');
         equal(options.ids[1], 'slave.driver');
 
-        return "HELP ME MY BOSS " + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
+        return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
       }
     };
 
@@ -41,7 +40,7 @@ describe('track ids', function() {
         equal(options.hashIds.bat, 'is.a');
         equal(options.hashIds.baz, 'slave.driver');
 
-        return "HELP ME MY BOSS " + options.hashIds.bat + ':' + options.hash.bat + ' ' + options.hashIds.baz + ':' + options.hash.baz;
+        return 'HELP ME MY BOSS ' + options.hashIds.bat + ':' + options.hash.bat + ' ' + options.hashIds.baz + ':' + options.hash.baz;
       }
     };
 
@@ -55,7 +54,7 @@ describe('track ids', function() {
         equal(options.ids[0], 'is.a');
         equal(options.ids[1], '../slave.driver');
 
-        return "HELP ME MY BOSS " + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
+        return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
       }
     };
 
@@ -69,11 +68,11 @@ describe('track ids', function() {
         equal(options.ids[0], '@is.a');
         equal(options.ids[1], '@slave.driver');
 
-        return "HELP ME MY BOSS " + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
+        return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
       }
     };
 
-    equals(template({}, {helpers: helpers, data:context}), 'HELP ME MY BOSS @is.a:foo @slave.driver:bar');
+    equals(template({}, {helpers: helpers, data: context}), 'HELP ME MY BOSS @is.a:foo @slave.driver:bar');
   });
 
   it('should return null for constants', function() {
@@ -85,7 +84,7 @@ describe('track ids', function() {
         equal(options.ids[1], null);
         equal(options.hashIds.key, null);
 
-        return "HELP ME MY BOSS " + passiveVoice + ' ' + noun + ' ' + options.hash.key;
+        return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun + ' ' + options.hash.key;
       }
     };
 
@@ -99,7 +98,7 @@ describe('track ids', function() {
       wycats: function(passiveVoice, options) {
         equal(options.ids[0], true);
 
-        return "HELP ME MY BOSS " + passiveVoice;
+        return 'HELP ME MY BOSS ' + passiveVoice;
       }
     };
 
@@ -120,7 +119,7 @@ describe('track ids', function() {
         equal(options.ids[1], 'slave.driver');
         equal(options.ids[2], 'zomg');
 
-        return "HELP ME MY BOSS " + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
+        return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
       }
     };
 
@@ -129,6 +128,9 @@ describe('track ids', function() {
 
   describe('builtin helpers', function() {
     var helpers = {
+      blockParams: function(name, options) {
+        return name + ':' + options.ids[0] + '\n';
+      },
       wycats: function(name, options) {
         return name + ':' + options.data.contextPath + '\n';
       }
@@ -151,13 +153,7 @@ describe('track ids', function() {
         equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:.array..0\nbar:.array..1\n');
       });
       it('should handle block params', function() {
-        var helpers = {
-          wycats: function(name, options) {
-            return name + ':' + options.ids[0] + '\n';
-          }
-        };
-
-        var template = CompilerContext.compile('{{#each array as |value|}}{{wycats value.name}}{{/each}}', {trackIds: true});
+        var template = CompilerContext.compile('{{#each array as |value|}}{{blockParams value.name}}{{/each}}', {trackIds: true});
 
         equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:array.0.name\nbar:array.1.name\n');
       });
diff --git a/spec/utils.js b/spec/utils.js
index 4582e2496..81732c5e7 100644
--- a/spec/utils.js
+++ b/spec/utils.js
@@ -1,19 +1,17 @@
-/*global Handlebars, shouldCompileTo */
-
 describe('utils', function() {
   describe('#SafeString', function() {
-    it("constructing a safestring from a string and checking its type", function() {
-      var safe = new Handlebars.SafeString("testing 1, 2, 3");
+    it('constructing a safestring from a string and checking its type', function() {
+      var safe = new Handlebars.SafeString('testing 1, 2, 3');
       if (!(safe instanceof Handlebars.SafeString)) {
         throw new Error('Must be instance of SafeString');
       }
-      equals(safe == 'testing 1, 2, 3', true, 'SafeString is equivalent to its underlying string');
+      equals(safe.toString(), 'testing 1, 2, 3', 'SafeString is equivalent to its underlying string');
     });
 
-    it("it should not escape SafeString properties", function() {
-      var name = new Handlebars.SafeString("<em>Sean O&#x27;Malley</em>");
+    it('it should not escape SafeString properties', function() {
+      var name = new Handlebars.SafeString('<em>Sean O&#x27;Malley</em>');
 
-      shouldCompileTo('{{name}}', [{ name: name }], "<em>Sean O&#x27;Malley</em>");
+      shouldCompileTo('{{name}}', [{name: name}], '<em>Sean O&#x27;Malley</em>');
     });
   });
 
diff --git a/spec/visitor.js b/spec/visitor.js
index 8b9ef9f60..1f50d79c1 100644
--- a/spec/visitor.js
+++ b/spec/visitor.js
@@ -1,5 +1,3 @@
-/*global Handlebars, shouldThrow */
-
 describe('Visitor', function() {
   if (!Handlebars.Visitor || !Handlebars.print) {
     return;
diff --git a/spec/whitespace-control.js b/spec/whitespace-control.js
index cce9405dd..a5c9bf14d 100644
--- a/spec/whitespace-control.js
+++ b/spec/whitespace-control.js
@@ -1,5 +1,3 @@
-/*global shouldCompileTo, shouldCompileToWithPartials */
-
 describe('whitespace control', function() {
   it('should strip whitespace around mustache calls', function() {
     var hash = {foo: 'bar<'};
diff --git a/tasks/version.js b/tasks/version.js
index c622a22fd..e6bfe5943 100644
--- a/tasks/version.js
+++ b/tasks/version.js
@@ -18,7 +18,7 @@ module.exports = function(grunt) {
     grunt.log.writeln('Updating to version ' + version);
 
     async.each([
-        ['lib/handlebars/base.js', /var VERSION = "(.*)";/, 'var VERSION = "' + version + '";'],
+        ['lib/handlebars/base.js', /var VERSION = ['"](.*)['"];/, 'var VERSION = "' + version + '";'],
         ['components/bower.json', /"version":.*/, '"version": "' + version + '",'],
         ['components/handlebars.js.nuspec', /<version>.*<\/version>/, '<version>' + version + '</version>']
       ],

From fdc94207a32ad60336a60cdb97b08726d10cae39 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Thu, 16 Apr 2015 16:54:24 -0500
Subject: [PATCH 12/17] Fix UMD build target generation

---
 Gruntfile.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gruntfile.js b/Gruntfile.js
index 48630046c..cff99459e 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -81,7 +81,7 @@ module.exports = function(grunt) {
         output: {
           path: 'dist/',
           library: 'Handlebars',
-          libraryType: 'umd'
+          libraryTarget: 'umd'
         }
       },
       handlebars: {

From ecf60ab1bfc2afb4202ec7a16f1754684825da39 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Mon, 20 Apr 2015 02:24:13 -0500
Subject: [PATCH 13/17] Enable additional es6 features in eslint

---
 .eslintrc      | 17 +++++++++++++++--
 lib/index.js   |  1 +
 spec/.eslintrc |  4 +++-
 3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/.eslintrc b/.eslintrc
index b6420d1f2..253a1bb29 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -6,7 +6,18 @@
     "node": true
   },
   "ecmaFeatures": {
-    "modules": true
+    // Enabling features that can be implemented without polyfills. Want to avoid polyfills at this time.
+    "arrowFunctions": true,
+    "blockBindings": true,
+    "defaultParams": true,
+    "destructuring": true,
+    "modules": true,
+    "objectLiteralComputedProperties": true,
+    "objectLiteralDuplicateProperties": true,
+    "objectLiteralShorthandMethods": true,
+    "objectLiteralShorthandProperties": true,
+    "spread": true,
+    "templateStrings": true
   },
   "rules": {
     // Possible Errors //
@@ -181,6 +192,8 @@
     "space-return-throw-case": 2,
     "space-unary-ops": 2,
     "spaced-line-comment": 2,
-    "wrap-regex": 1
+    "wrap-regex": 1,
+
+    "no-var": 1
   }
 }
\ No newline at end of file
diff --git a/lib/index.js b/lib/index.js
index ac559674a..0383c02f7 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -1,5 +1,6 @@
 // USAGE:
 // var handlebars = require('handlebars');
+/* eslint-disable no-var */
 
 // var local = handlebars.create();
 
diff --git a/spec/.eslintrc b/spec/.eslintrc
index 2d0581468..21871d52f 100644
--- a/spec/.eslintrc
+++ b/spec/.eslintrc
@@ -29,6 +29,8 @@
   },
   "rules": {
     // Disabling for tests, for now.
-    "no-path-concat": 0
+    "no-path-concat": 0,
+
+    "no-var": 0
   }
 }
\ No newline at end of file

From 0263aa48bc8c8cdcd332edd01a644a9a0fd1cc81 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Mon, 20 Apr 2015 02:25:53 -0500
Subject: [PATCH 14/17] Run the precompiler module through es6 toolchain

---
 Gruntfile.js        |  2 +-
 bin/handlebars      |  2 +-
 lib/precompiler.js  | 34 ++++++++++++++++------------------
 spec/precompiler.js |  2 +-
 4 files changed, 19 insertions(+), 21 deletions(-)

diff --git a/Gruntfile.js b/Gruntfile.js
index cff99459e..70239bf8b 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -52,7 +52,7 @@ module.exports = function(grunt) {
         files: [{
           expand: true,
           cwd: 'lib/',
-          src: '**/!(index|precompiler).js',
+          src: '**/!(index).js',
           dest: 'dist/amd/'
         }]
       },
diff --git a/bin/handlebars b/bin/handlebars
index bf64784aa..4ed98b372 100755
--- a/bin/handlebars
+++ b/bin/handlebars
@@ -108,4 +108,4 @@ if (argv.help || (!argv.templates.length && !argv.version)) {
   return;
 }
 
-return require('../lib/precompiler').cli(argv);
+return require('../dist/cjs/precompiler').cli(argv);
diff --git a/lib/precompiler.js b/lib/precompiler.js
index f0955e7ff..48cfebd1a 100644
--- a/lib/precompiler.js
+++ b/lib/precompiler.js
@@ -1,11 +1,9 @@
 /*eslint-disable no-console */
-var fs = require('fs'),
-    Handlebars = require('./index'),
-    basename = require('path').basename,
-    SourceMap = require('source-map'),
-      SourceMapConsumer = SourceMap.SourceMapConsumer,
-      SourceNode = SourceMap.SourceNode,
-    uglify = require('uglify-js');
+import fs from 'fs';
+import * as Handlebars from './handlebars';
+import {basename} from 'path';
+import {SourceMapConsumer, SourceNode} from 'source-map';
+import uglify from 'uglify-js';
 
 module.exports.cli = function(opts) {
   if (opts.version) {
@@ -21,7 +19,7 @@ module.exports.cli = function(opts) {
     try {
       fs.statSync(template);
     } catch (err) {
-      throw new Handlebars.Exception('Unable to open template file "' + template + '"');
+      throw new Handlebars.Exception(`Unable to open template file "${template}"`);
     }
   });
 
@@ -33,21 +31,21 @@ module.exports.cli = function(opts) {
   }
 
   // Convert the known list into a hash
-  var known = {};
+  let known = {};
   if (opts.known && !Array.isArray(opts.known)) {
     opts.known = [opts.known];
   }
   if (opts.known) {
-    for (var i = 0, len = opts.known.length; i < len; i++) {
+    for (let i = 0, len = opts.known.length; i < len; i++) {
       known[opts.known[i]] = true;
     }
   }
 
   // Build file extension pattern
-  var extension = opts.extension.replace(/[\\^$*+?.():=!|{}\-\[\]]/g, function(arg) { return '\\' + arg; });
+  let extension = opts.extension.replace(/[\\^$*+?.():=!|{}\-\[\]]/g, function(arg) { return '\\' + arg; });
   extension = new RegExp('\\.' + extension + '$');
 
-  var output = new SourceNode();
+  let output = new SourceNode();
   if (!opts.simple) {
     if (opts.amd) {
       output.add('define([\'' + opts.handlebarPath + 'handlebars.runtime\'], function(Handlebars) {\n  Handlebars = Handlebars["default"];');
@@ -66,24 +64,24 @@ module.exports.cli = function(opts) {
     output.add('{};\n');
   }
   function processTemplate(template, root) {
-    var path = template,
+    let path = template,
         stat = fs.statSync(path);
     if (stat.isDirectory()) {
       fs.readdirSync(template).map(function(file) {
-        var childPath = template + '/' + file;
+        let childPath = template + '/' + file;
 
         if (extension.test(childPath) || fs.statSync(childPath).isDirectory()) {
           processTemplate(childPath, root || template);
         }
       });
     } else {
-      var data = fs.readFileSync(path, 'utf8');
+      let data = fs.readFileSync(path, 'utf8');
 
       if (opts.bom && data.indexOf('\uFEFF') === 0) {
         data = data.substring(1);
       }
 
-      var options = {
+      let options = {
         knownHelpers: known,
         knownHelpersOnly: opts.o
       };
@@ -103,11 +101,11 @@ module.exports.cli = function(opts) {
       }
       template = template.replace(extension, '');
 
-      var precompiled = Handlebars.precompile(data, options);
+      let precompiled = Handlebars.precompile(data, options);
 
       // If we are generating a source map, we have to reconstruct the SourceNode object
       if (opts.map) {
-        var consumer = new SourceMapConsumer(precompiled.map);
+        let consumer = new SourceMapConsumer(precompiled.map);
         precompiled = SourceNode.fromStringWithSourceMap(precompiled.code, consumer);
       }
 
diff --git a/spec/precompiler.js b/spec/precompiler.js
index f877c2911..21e25b06e 100644
--- a/spec/precompiler.js
+++ b/spec/precompiler.js
@@ -6,7 +6,7 @@ describe('precompiler', function() {
   }
 
   var Handlebars = require('../lib'),
-      Precompiler = require('../lib/precompiler'),
+      Precompiler = require('../dist/cjs/precompiler'),
       fs = require('fs'),
       uglify = require('uglify-js');
 

From 4bed826d0e210c336fb9e500835b1c1926562da5 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Mon, 20 Apr 2015 02:38:28 -0500
Subject: [PATCH 15/17] Update for let and optional parameters

---
 lib/handlebars.js                             |   8 +-
 lib/handlebars.runtime.js                     |   6 +-
 lib/handlebars/base.js                        |  47 +++---
 lib/handlebars/compiler/ast.js                |   2 +-
 lib/handlebars/compiler/base.js               |   4 +-
 lib/handlebars/compiler/code-gen.js           |  32 ++---
 lib/handlebars/compiler/compiler.js           | 100 ++++++-------
 lib/handlebars/compiler/helpers.js            |  16 +--
 .../compiler/javascript-compiler.js           | 135 +++++++++---------
 lib/handlebars/compiler/printer.js            |  26 ++--
 lib/handlebars/compiler/visitor.js            |   6 +-
 lib/handlebars/compiler/whitespace-control.js |  30 ++--
 lib/handlebars/exception.js                   |   8 +-
 lib/handlebars/runtime.js                     |  35 +++--
 lib/handlebars/utils.js                       |  20 +--
 15 files changed, 236 insertions(+), 239 deletions(-)

diff --git a/lib/handlebars.js b/lib/handlebars.js
index 38144a363..3e566a798 100644
--- a/lib/handlebars.js
+++ b/lib/handlebars.js
@@ -7,9 +7,9 @@ import { Compiler, compile, precompile } from './handlebars/compiler/compiler';
 import JavaScriptCompiler from './handlebars/compiler/javascript-compiler';
 import Visitor from './handlebars/compiler/visitor';
 
-var _create = Handlebars.create;
+let _create = Handlebars.create;
 function create() {
-  var hb = _create();
+  let hb = _create();
 
   hb.compile = function(input, options) {
     return compile(input, options, hb);
@@ -27,14 +27,14 @@ function create() {
   return hb;
 }
 
-var inst = create();
+let inst = create();
 inst.create = create;
 
 inst.Visitor = Visitor;
 
 /*jshint -W040 */
 /* istanbul ignore next */
-var $Handlebars = global.Handlebars;
+let $Handlebars = global.Handlebars;
 /* istanbul ignore next */
 inst.noConflict = function() {
   if (global.Handlebars === inst) {
diff --git a/lib/handlebars.runtime.js b/lib/handlebars.runtime.js
index c502b5ca7..e7b149b73 100644
--- a/lib/handlebars.runtime.js
+++ b/lib/handlebars.runtime.js
@@ -10,7 +10,7 @@ import * as runtime from './handlebars/runtime';
 
 // For compatibility and usage outside of module systems, make the Handlebars object a namespace
 function create() {
-  var hb = new base.HandlebarsEnvironment();
+  let hb = new base.HandlebarsEnvironment();
 
   Utils.extend(hb, base);
   hb.SafeString = SafeString;
@@ -26,12 +26,12 @@ function create() {
   return hb;
 }
 
-var Handlebars = create();
+let Handlebars = create();
 Handlebars.create = create;
 
 /*jshint -W040 */
 /* istanbul ignore next */
-var root = typeof global !== 'undefined' ? global : window,
+let root = typeof global !== 'undefined' ? global : window,
     $Handlebars = root.Handlebars;
 /* istanbul ignore next */
 Handlebars.noConflict = function() {
diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js
index 771cb9ccf..cfe1e917c 100644
--- a/lib/handlebars/base.js
+++ b/lib/handlebars/base.js
@@ -1,10 +1,10 @@
 import * as Utils from './utils';
 import Exception from './exception';
 
-export var VERSION = '3.0.1';
-export var COMPILER_REVISION = 6;
+export const VERSION = '3.0.1';
+export const COMPILER_REVISION = 6;
 
-export var REVISION_CHANGES = {
+export const REVISION_CHANGES = {
   1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
   2: '== 1.0.0-rc.3',
   3: '== 1.0.0-rc.4',
@@ -13,10 +13,10 @@ export var REVISION_CHANGES = {
   6: '>= 2.0.0-beta.1'
 };
 
-var isArray = Utils.isArray,
-    isFunction = Utils.isFunction,
-    toString = Utils.toString,
-    objectType = '[object Object]';
+const isArray = Utils.isArray,
+      isFunction = Utils.isFunction,
+      toString = Utils.toString,
+      objectType = '[object Object]';
 
 export function HandlebarsEnvironment(helpers, partials) {
   this.helpers = helpers || {};
@@ -70,7 +70,7 @@ function registerDefaultHelpers(instance) {
   });
 
   instance.registerHelper('blockHelperMissing', function(context, options) {
-    var inverse = options.inverse,
+    let inverse = options.inverse,
         fn = options.fn;
 
     if (context === true) {
@@ -89,7 +89,7 @@ function registerDefaultHelpers(instance) {
       }
     } else {
       if (options.data && options.ids) {
-        var data = createFrame(options.data);
+        let data = createFrame(options.data);
         data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name);
         options = {data: data};
       }
@@ -103,10 +103,13 @@ function registerDefaultHelpers(instance) {
       throw new Exception('Must pass iterator to #each');
     }
 
-    var fn = options.fn, inverse = options.inverse;
-    var i = 0, ret = '', data;
+    let fn = options.fn,
+        inverse = options.inverse,
+        i = 0,
+        ret = '',
+        data,
+        contextPath;
 
-    var contextPath;
     if (options.data && options.ids) {
       contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.';
     }
@@ -137,13 +140,13 @@ function registerDefaultHelpers(instance) {
 
     if (context && typeof context === 'object') {
       if (isArray(context)) {
-        for (var j = context.length; i < j; i++) {
+        for (let j = context.length; i < j; i++) {
           execIteration(i, i, i === context.length - 1);
         }
       } else {
-        var priorKey;
+        let priorKey;
 
-        for (var key in context) {
+        for (let key in context) {
           if (context.hasOwnProperty(key)) {
             // We're running the iterations one step out of sync so we can detect
             // the last iteration without have to scan the object twice and create
@@ -188,11 +191,11 @@ function registerDefaultHelpers(instance) {
   instance.registerHelper('with', function(context, options) {
     if (isFunction(context)) { context = context.call(this); }
 
-    var fn = options.fn;
+    let fn = options.fn;
 
     if (!Utils.isEmpty(context)) {
       if (options.data && options.ids) {
-        var data = createFrame(options.data);
+        let data = createFrame(options.data);
         data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]);
         options = {data: data};
       }
@@ -204,7 +207,7 @@ function registerDefaultHelpers(instance) {
   });
 
   instance.registerHelper('log', function(message, options) {
-    var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
+    let level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
     instance.log(level, message);
   });
 
@@ -213,7 +216,7 @@ function registerDefaultHelpers(instance) {
   });
 }
 
-export var logger = {
+export let logger = {
   methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' },
 
   // State enum
@@ -226,16 +229,16 @@ export var logger = {
   // Can be overridden in the host environment
   log: function(level, message) {
     if (typeof console !== 'undefined' && logger.level <= level) {
-      var method = logger.methodMap[level];
+      let method = logger.methodMap[level];
       (console[method] || console.log).call(console, message);    // eslint-disable-line no-console
     }
   }
 };
 
-export var log = logger.log;
+export let log = logger.log;
 
 export function createFrame(object) {
-  var frame = Utils.extend({}, object);
+  let frame = Utils.extend({}, object);
   frame._parent = object;
   return frame;
 }
diff --git a/lib/handlebars/compiler/ast.js b/lib/handlebars/compiler/ast.js
index 1ecf59b5e..08b127f77 100644
--- a/lib/handlebars/compiler/ast.js
+++ b/lib/handlebars/compiler/ast.js
@@ -1,4 +1,4 @@
-var AST = {
+let AST = {
   Program: function(statements, blockParams, strip, locInfo) {
     this.loc = locInfo;
     this.type = 'Program';
diff --git a/lib/handlebars/compiler/base.js b/lib/handlebars/compiler/base.js
index 02e174fe8..7075d9bd8 100644
--- a/lib/handlebars/compiler/base.js
+++ b/lib/handlebars/compiler/base.js
@@ -6,7 +6,7 @@ import { extend } from '../utils';
 
 export { parser };
 
-var yy = {};
+let yy = {};
 extend(yy, Helpers, AST);
 
 export function parse(input, options) {
@@ -20,6 +20,6 @@ export function parse(input, options) {
     return new yy.SourceLocation(options && options.srcName, locInfo);
   };
 
-  var strip = new WhitespaceControl();
+  let strip = new WhitespaceControl();
   return strip.accept(parser.parse(input));
 }
diff --git a/lib/handlebars/compiler/code-gen.js b/lib/handlebars/compiler/code-gen.js
index 0c40e00f0..bc7bc0703 100644
--- a/lib/handlebars/compiler/code-gen.js
+++ b/lib/handlebars/compiler/code-gen.js
@@ -1,14 +1,14 @@
 /*global define */
 import {isArray} from '../utils';
 
-var SourceNode;
+let SourceNode;
 
 try {
   /* istanbul ignore next */
   if (typeof define !== 'function' || !define.amd) {
     // We don't support this in AMD environments. For these environments, we asusme that
     // they are running on the browser and thus have no need for the source-map library.
-    var SourceMap = require('source-map');
+    let SourceMap = require('source-map');
     SourceNode = SourceMap.SourceNode;
   }
 } catch (err) {
@@ -49,9 +49,9 @@ if (!SourceNode) {
 
 function castChunk(chunk, codeGen, loc) {
   if (isArray(chunk)) {
-    var ret = [];
+    let ret = [];
 
-    for (var i = 0, len = chunk.length; i < len; i++) {
+    for (let i = 0, len = chunk.length; i < len; i++) {
       ret.push(codeGen.wrap(chunk[i], loc));
     }
     return ret;
@@ -77,7 +77,7 @@ CodeGen.prototype = {
   },
 
   merge: function() {
-    var source = this.empty();
+    let source = this.empty();
     this.each(function(line) {
       source.add(['  ', line, '\n']);
     });
@@ -85,21 +85,19 @@ CodeGen.prototype = {
   },
 
   each: function(iter) {
-    for (var i = 0, len = this.source.length; i < len; i++) {
+    for (let i = 0, len = this.source.length; i < len; i++) {
       iter(this.source[i]);
     }
   },
 
-  empty: function(loc) {
-    loc = loc || this.currentLocation || {start: {}};
+  empty: function(loc = this.currentLocation || {start: {}}) {
     return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
   },
-  wrap: function(chunk, loc) {
+  wrap: function(chunk, loc = this.currentLocation || {start: {}}) {
     if (chunk instanceof SourceNode) {
       return chunk;
     }
 
-    loc = loc || this.currentLocation || {start: {}};
     chunk = castChunk(chunk, this, loc);
 
     return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk);
@@ -121,18 +119,18 @@ CodeGen.prototype = {
   },
 
   objectLiteral: function(obj) {
-    var pairs = [];
+    let pairs = [];
 
-    for (var key in obj) {
+    for (let key in obj) {
       if (obj.hasOwnProperty(key)) {
-        var value = castChunk(obj[key], this);
+        let value = castChunk(obj[key], this);
         if (value !== 'undefined') {
           pairs.push([this.quotedString(key), ':', value]);
         }
       }
     }
 
-    var ret = this.generateList(pairs);
+    let ret = this.generateList(pairs);
     ret.prepend('{');
     ret.add('}');
     return ret;
@@ -140,9 +138,9 @@ CodeGen.prototype = {
 
 
   generateList: function(entries, loc) {
-    var ret = this.empty(loc);
+    let ret = this.empty(loc);
 
-    for (var i = 0, len = entries.length; i < len; i++) {
+    for (let i = 0, len = entries.length; i < len; i++) {
       if (i) {
         ret.add(',');
       }
@@ -154,7 +152,7 @@ CodeGen.prototype = {
   },
 
   generateArray: function(entries, loc) {
-    var ret = this.generateList(entries, loc);
+    let ret = this.generateList(entries, loc);
     ret.prepend('[');
     ret.add(']');
 
diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js
index a9bfc8564..457542162 100644
--- a/lib/handlebars/compiler/compiler.js
+++ b/lib/handlebars/compiler/compiler.js
@@ -2,8 +2,7 @@ import Exception from '../exception';
 import {isArray, indexOf} from '../utils';
 import AST from './ast';
 
-var slice = [].slice;
-
+const slice = [].slice;
 
 export function Compiler() {}
 
@@ -16,13 +15,13 @@ Compiler.prototype = {
   compiler: Compiler,
 
   equals: function(other) {
-    var len = this.opcodes.length;
+    let len = this.opcodes.length;
     if (other.opcodes.length !== len) {
       return false;
     }
 
-    for (var i = 0; i < len; i++) {
-      var opcode = this.opcodes[i],
+    for (let i = 0; i < len; i++) {
+      let opcode = this.opcodes[i],
           otherOpcode = other.opcodes[i];
       if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) {
         return false;
@@ -32,7 +31,7 @@ Compiler.prototype = {
     // We know that length is the same between the two arrays because they are directly tied
     // to the opcode behavior above.
     len = this.children.length;
-    for (i = 0; i < len; i++) {
+    for (let i = 0; i < len; i++) {
       if (!this.children[i].equals(other.children[i])) {
         return false;
       }
@@ -54,7 +53,7 @@ Compiler.prototype = {
     options.blockParams = options.blockParams || [];
 
     // These changes will propagate to the other compiler components
-    var knownHelpers = options.knownHelpers;
+    let knownHelpers = options.knownHelpers;
     options.knownHelpers = {
       'helperMissing': true,
       'blockHelperMissing': true,
@@ -66,7 +65,7 @@ Compiler.prototype = {
       'lookup': true
     };
     if (knownHelpers) {
-      for (var name in knownHelpers) {
+      for (let name in knownHelpers) {
         if (name in knownHelpers) {
           options.knownHelpers[name] = knownHelpers[name];
         }
@@ -77,8 +76,9 @@ Compiler.prototype = {
   },
 
   compileProgram: function(program) {
-    var result = new this.compiler().compile(program, this.options); // eslint-disable-line new-cap
-    var guid = this.guid++;
+    let childCompiler = new this.compiler(), // eslint-disable-line new-cap
+        result = childCompiler.compile(program, this.options),
+        guid = this.guid++;
 
     this.usePartial = this.usePartial || result.usePartial;
 
@@ -90,7 +90,7 @@ Compiler.prototype = {
 
   accept: function(node) {
     this.sourceNode.unshift(node);
-    var ret = this[node.type](node);
+    let ret = this[node.type](node);
     this.sourceNode.shift();
     return ret;
   },
@@ -98,14 +98,15 @@ Compiler.prototype = {
   Program: function(program) {
     this.options.blockParams.unshift(program.blockParams);
 
-    var body = program.body;
-    for (var i = 0, l = body.length; i < l; i++) {
+    let body = program.body,
+        bodyLength = body.length;
+    for (let i = 0; i < bodyLength; i++) {
       this.accept(body[i]);
     }
 
     this.options.blockParams.shift();
 
-    this.isSimple = l === 1;
+    this.isSimple = bodyLength === 1;
     this.blockParams = program.blockParams ? program.blockParams.length : 0;
 
     return this;
@@ -114,13 +115,13 @@ Compiler.prototype = {
   BlockStatement: function(block) {
     transformLiteralToPath(block);
 
-    var program = block.program,
+    let program = block.program,
         inverse = block.inverse;
 
     program = program && this.compileProgram(program);
     inverse = inverse && this.compileProgram(inverse);
 
-    var type = this.classifySexpr(block);
+    let type = this.classifySexpr(block);
 
     if (type === 'helper') {
       this.helperSexpr(block, program, inverse);
@@ -150,14 +151,14 @@ Compiler.prototype = {
   PartialStatement: function(partial) {
     this.usePartial = true;
 
-    var params = partial.params;
+    let params = partial.params;
     if (params.length > 1) {
       throw new Exception('Unsupported number of partial arguments: ' + params.length, partial);
     } else if (!params.length) {
       params.push({type: 'PathExpression', parts: [], depth: 0});
     }
 
-    var partialName = partial.name.original,
+    let partialName = partial.name.original,
         isDynamic = partial.name.type === 'SubExpression';
     if (isDynamic) {
       this.accept(partial.name);
@@ -165,7 +166,7 @@ Compiler.prototype = {
 
     this.setupFullMustacheParams(partial, undefined, undefined, true);
 
-    var indent = partial.indent || '';
+    let indent = partial.indent || '';
     if (this.options.preventIndent && indent) {
       this.opcode('appendContent', indent);
       indent = '';
@@ -195,7 +196,7 @@ Compiler.prototype = {
 
   SubExpression: function(sexpr) {
     transformLiteralToPath(sexpr);
-    var type = this.classifySexpr(sexpr);
+    let type = this.classifySexpr(sexpr);
 
     if (type === 'simple') {
       this.simpleSexpr(sexpr);
@@ -206,7 +207,7 @@ Compiler.prototype = {
     }
   },
   ambiguousSexpr: function(sexpr, program, inverse) {
-    var path = sexpr.path,
+    let path = sexpr.path,
         name = path.parts[0],
         isBlock = program != null || inverse != null;
 
@@ -226,7 +227,7 @@ Compiler.prototype = {
   },
 
   helperSexpr: function(sexpr, program, inverse) {
-    var params = this.setupFullMustacheParams(sexpr, program, inverse),
+    let params = this.setupFullMustacheParams(sexpr, program, inverse),
         path = sexpr.path,
         name = path.parts[0];
 
@@ -246,7 +247,7 @@ Compiler.prototype = {
     this.addDepth(path.depth);
     this.opcode('getContext', path.depth);
 
-    var name = path.parts[0],
+    let name = path.parts[0],
         scoped = AST.helpers.scopedId(path),
         blockParamId = !path.depth && !scoped && this.blockParamIndex(name);
 
@@ -284,11 +285,13 @@ Compiler.prototype = {
   },
 
   Hash: function(hash) {
-    var pairs = hash.pairs, i, l;
+    let pairs = hash.pairs,
+        i = 0,
+        l = pairs.length;
 
     this.opcode('pushHash');
 
-    for (i = 0, l = pairs.length; i < l; i++) {
+    for (; i < l; i++) {
       this.pushParam(pairs[i].value);
     }
     while (i--) {
@@ -311,25 +314,24 @@ Compiler.prototype = {
   },
 
   classifySexpr: function(sexpr) {
-    var isSimple = AST.helpers.simpleId(sexpr.path);
+    let isSimple = AST.helpers.simpleId(sexpr.path);
 
-    var isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]);
+    let isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]);
 
     // a mustache is an eligible helper if:
     // * its id is simple (a single part, not `this` or `..`)
-    var isHelper = !isBlockParam && AST.helpers.helperExpression(sexpr);
+    let isHelper = !isBlockParam && AST.helpers.helperExpression(sexpr);
 
     // if a mustache is an eligible helper but not a definite
     // helper, it is ambiguous, and will be resolved in a later
     // pass or at runtime.
-    var isEligible = !isBlockParam && (isHelper || isSimple);
-
-    var options = this.options;
+    let isEligible = !isBlockParam && (isHelper || isSimple);
 
     // if ambiguous, we can possibly resolve the ambiguity now
     // An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc.
     if (isEligible && !isHelper) {
-      var name = sexpr.path.parts[0];
+      let name = sexpr.path.parts[0],
+          options = this.options;
 
       if (options.knownHelpers[name]) {
         isHelper = true;
@@ -348,13 +350,13 @@ Compiler.prototype = {
   },
 
   pushParams: function(params) {
-    for (var i = 0, l = params.length; i < l; i++) {
+    for (let i = 0, l = params.length; i < l; i++) {
       this.pushParam(params[i]);
     }
   },
 
   pushParam: function(val) {
-    var value = val.value != null ? val.value : val.original || '';
+    let value = val.value != null ? val.value : val.original || '';
 
     if (this.stringParams) {
       if (value.replace) {
@@ -376,12 +378,12 @@ Compiler.prototype = {
       }
     } else {
       if (this.trackIds) {
-        var blockParamIndex;
+        let blockParamIndex;
         if (val.parts && !AST.helpers.scopedId(val) && !val.depth) {
            blockParamIndex = this.blockParamIndex(val.parts[0]);
         }
         if (blockParamIndex) {
-          var blockParamChild = val.parts.slice(1).join('.');
+          let blockParamChild = val.parts.slice(1).join('.');
           this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild);
         } else {
           value = val.original || value;
@@ -399,7 +401,7 @@ Compiler.prototype = {
   },
 
   setupFullMustacheParams: function(sexpr, program, inverse, omitEmpty) {
-    var params = sexpr.params;
+    let params = sexpr.params;
     this.pushParams(params);
 
     this.opcode('pushProgram', program);
@@ -415,8 +417,8 @@ Compiler.prototype = {
   },
 
   blockParamIndex: function(name) {
-    for (var depth = 0, len = this.options.blockParams.length; depth < len; depth++) {
-      var blockParams = this.options.blockParams[depth],
+    for (let depth = 0, len = this.options.blockParams.length; depth < len; depth++) {
+      let blockParams = this.options.blockParams[depth],
           param = blockParams && indexOf(blockParams, name);
       if (blockParams && param >= 0) {
         return [depth, param];
@@ -438,18 +440,16 @@ export function precompile(input, options, env) {
     options.useDepths = true;
   }
 
-  var ast = env.parse(input, options);
-  var environment = new env.Compiler().compile(ast, options);
+  let ast = env.parse(input, options),
+      environment = new env.Compiler().compile(ast, options);
   return new env.JavaScriptCompiler().compile(environment, options);
 }
 
-export function compile(input, options, env) {
+export function compile(input, options = {}, env) {
   if (input == null || (typeof input !== 'string' && input.type !== 'Program')) {
     throw new Exception('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input);
   }
 
-  options = options || {};
-
   if (!('data' in options)) {
     options.data = true;
   }
@@ -457,12 +457,12 @@ export function compile(input, options, env) {
     options.useDepths = true;
   }
 
-  var compiled;
+  let compiled;
 
   function compileInput() {
-    var ast = env.parse(input, options);
-    var environment = new env.Compiler().compile(ast, options);
-    var templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true);
+    let ast = env.parse(input, options),
+        environment = new env.Compiler().compile(ast, options),
+        templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true);
     return env.template(templateSpec);
   }
 
@@ -494,7 +494,7 @@ function argEquals(a, b) {
   }
 
   if (isArray(a) && isArray(b) && a.length === b.length) {
-    for (var i = 0; i < a.length; i++) {
+    for (let i = 0; i < a.length; i++) {
       if (!argEquals(a[i], b[i])) {
         return false;
       }
@@ -505,7 +505,7 @@ function argEquals(a, b) {
 
 function transformLiteralToPath(sexpr) {
   if (!sexpr.path.parts) {
-    var literal = sexpr.path;
+    let literal = sexpr.path;
     // Casting to string here to make false and 0 literal values play nicely with the rest
     // of the system.
     sexpr.path = new AST.PathExpression(false, 0, [literal.original + ''], literal.original + '', literal.loc);
diff --git a/lib/handlebars/compiler/helpers.js b/lib/handlebars/compiler/helpers.js
index 7f784adf5..31daf6df9 100644
--- a/lib/handlebars/compiler/helpers.js
+++ b/lib/handlebars/compiler/helpers.js
@@ -36,13 +36,13 @@ export function preparePath(data, parts, locInfo) {
   /*jshint -W040 */
   locInfo = this.locInfo(locInfo);
 
-  var original = data ? '@' : '',
+  let original = data ? '@' : '',
       dig = [],
       depth = 0,
       depthString = '';
 
-  for (var i = 0, l = parts.length; i < l; i++) {
-    var part = parts[i].part,
+  for (let i = 0, l = parts.length; i < l; i++) {
+    let part = parts[i].part,
         // If we have [] syntax then we do not treat path references as operators,
         // i.e. foo.[this] resolves to approximately context.foo['this']
         isLiteral = parts[i].original !== part;
@@ -66,7 +66,7 @@ export function preparePath(data, parts, locInfo) {
 export function prepareMustache(path, params, hash, open, strip, locInfo) {
   /*jshint -W040 */
   // Must use charAt to support IE pre-10
-  var escapeFlag = open.charAt(3) || open.charAt(2),
+  let escapeFlag = open.charAt(3) || open.charAt(2),
       escaped = escapeFlag !== '{' && escapeFlag !== '&';
 
   return new this.MustacheStatement(path, params, hash, escaped, strip, this.locInfo(locInfo));
@@ -75,13 +75,13 @@ export function prepareMustache(path, params, hash, open, strip, locInfo) {
 export function prepareRawBlock(openRawBlock, content, close, locInfo) {
   /*jshint -W040 */
   if (openRawBlock.path.original !== close) {
-    var errorNode = {loc: openRawBlock.path.loc};
+    let errorNode = {loc: openRawBlock.path.loc};
 
     throw new Exception(openRawBlock.path.original + " doesn't match " + close, errorNode);
   }
 
   locInfo = this.locInfo(locInfo);
-  var program = new this.Program([content], null, {}, locInfo);
+  let program = new this.Program([content], null, {}, locInfo);
 
   return new this.BlockStatement(
       openRawBlock.path, openRawBlock.params, openRawBlock.hash,
@@ -94,14 +94,14 @@ export function prepareBlock(openBlock, program, inverseAndProgram, close, inver
   /*jshint -W040 */
   // When we are chaining inverse calls, we will not have a close path
   if (close && close.path && openBlock.path.original !== close.path.original) {
-    var errorNode = {loc: openBlock.path.loc};
+    let errorNode = {loc: openBlock.path.loc};
 
     throw new Exception(openBlock.path.original + ' doesn\'t match ' + close.path.original, errorNode);
   }
 
   program.blockParams = openBlock.blockParams;
 
-  var inverse,
+  let inverse,
       inverseStrip;
 
   if (inverseAndProgram) {
diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js
index e27816284..75e50d2fe 100644
--- a/lib/handlebars/compiler/javascript-compiler.js
+++ b/lib/handlebars/compiler/javascript-compiler.js
@@ -24,8 +24,8 @@ JavaScriptCompiler.prototype = {
   },
 
   compilerInfo: function() {
-    var revision = COMPILER_REVISION,
-        versions = REVISION_CHANGES[revision];
+    const revision = COMPILER_REVISION,
+          versions = REVISION_CHANGES[revision];
     return [revision, versions];
   },
 
@@ -84,7 +84,7 @@ JavaScriptCompiler.prototype = {
     this.useDepths = this.useDepths || environment.useDepths || this.options.compat;
     this.useBlockParams = this.useBlockParams || environment.useBlockParams;
 
-    var opcodes = environment.opcodes,
+    let opcodes = environment.opcodes,
         opcode,
         firstLoc,
         i,
@@ -107,13 +107,13 @@ JavaScriptCompiler.prototype = {
       throw new Exception('Compile completed with content left on stack');
     }
 
-    var fn = this.createFunctionContext(asObject);
+    let fn = this.createFunctionContext(asObject);
     if (!this.isChild) {
-      var ret = {
+      let ret = {
         compiler: this.compilerInfo(),
         main: fn
       };
-      var programs = this.context.programs;
+      let programs = this.context.programs;
       for (i = 0, l = programs.length; i < l; i++) {
         if (programs[i]) {
           ret[i] = programs[i];
@@ -166,9 +166,9 @@ JavaScriptCompiler.prototype = {
   },
 
   createFunctionContext: function(asObject) {
-    var varDeclarations = '';
+    let varDeclarations = '';
 
-    var locals = this.stackVars.concat(this.registers.list);
+    let locals = this.stackVars.concat(this.registers.list);
     if (locals.length > 0) {
       varDeclarations += ', ' + locals.join(', ');
     }
@@ -179,9 +179,9 @@ JavaScriptCompiler.prototype = {
     // as the source nodes are reused in situ. For the non-source node compilation mode,
     // aliases will not be used, but this case is already being run on the client and
     // we aren't concern about minimizing the template size.
-    var aliasCount = 0;
-    for (var alias in this.aliases) {    // eslint-disable-line guard-for-in
-      var node = this.aliases[alias];
+    let aliasCount = 0;
+    for (let alias in this.aliases) {    // eslint-disable-line guard-for-in
+      let node = this.aliases[alias];
 
       if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) {
         varDeclarations += ', alias' + (++aliasCount) + '=' + alias;
@@ -189,7 +189,7 @@ JavaScriptCompiler.prototype = {
       }
     }
 
-    var params = ['depth0', 'helpers', 'partials', 'data'];
+    let params = ['depth0', 'helpers', 'partials', 'data'];
 
     if (this.useBlockParams || this.useDepths) {
       params.push('blockParams');
@@ -199,7 +199,7 @@ JavaScriptCompiler.prototype = {
     }
 
     // Perform a second pass over the output to merge content when possible
-    var source = this.mergeSource(varDeclarations);
+    let source = this.mergeSource(varDeclarations);
 
     if (asObject) {
       params.push(source);
@@ -210,14 +210,14 @@ JavaScriptCompiler.prototype = {
     }
   },
   mergeSource: function(varDeclarations) {
-    var isSimple = this.environment.isSimple,
+    let isSimple = this.environment.isSimple,
         appendOnly = !this.forceBuffer,
         appendFirst,
 
         sourceSeen,
         bufferStart,
         bufferEnd;
-    this.source.each(function(line) {
+    this.source.each((line) => {
       if (line.appendToBuffer) {
         if (bufferStart) {
           line.prepend('  + ');
@@ -279,11 +279,11 @@ JavaScriptCompiler.prototype = {
   // replace it on the stack with the result of properly
   // invoking blockHelperMissing.
   blockValue: function(name) {
-    var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
+    let blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
         params = [this.contextName(0)];
     this.setupHelperArgs(name, 0, params);
 
-    var blockName = this.popStack();
+    let blockName = this.popStack();
     params.splice(1, 0, blockName);
 
     this.push(this.source.functionCall(blockHelperMissing, 'call', params));
@@ -297,13 +297,13 @@ JavaScriptCompiler.prototype = {
   // On stack, after, if lastHelper: value
   ambiguousBlockValue: function() {
     // We're being a bit cheeky and reusing the options value from the prior exec
-    var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
+    let blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
         params = [this.contextName(0)];
     this.setupHelperArgs('', 0, params, true);
 
     this.flushInline();
 
-    var current = this.topStack();
+    let current = this.topStack();
     params.splice(1, 0, current);
 
     this.pushSource([
@@ -339,13 +339,11 @@ JavaScriptCompiler.prototype = {
   // Otherwise, the empty string is appended
   append: function() {
     if (this.isInline()) {
-      this.replaceStack(function(current) {
-        return [' != null ? ', current, ' : ""'];
-      });
+      this.replaceStack((current) => [' != null ? ', current, ' : ""']);
 
       this.pushSource(this.appendToBuffer(this.popStack()));
     } else {
-      var local = this.popStack();
+      let local = this.popStack();
       this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']);
       if (this.environment.isSimple) {
         this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']);
@@ -393,7 +391,7 @@ JavaScriptCompiler.prototype = {
   // Looks up the value of `name` on the current context and pushes
   // it onto the stack.
   lookupOnContext: function(parts, falsy, scoped) {
-    var i = 0;
+    let i = 0;
 
     if (!scoped && this.options.compat && !this.lastContext) {
       // The depthed query is expected to handle the undefined logic for the root level that
@@ -444,11 +442,11 @@ JavaScriptCompiler.prototype = {
       return;
     }
 
-    var len = parts.length;
+    let len = parts.length;
     for (; i < len; i++) {
       /*eslint-disable no-loop-func */
-      this.replaceStack(function(current) {
-        var lookup = this.nameLookup(current, parts[i], type);
+      this.replaceStack((current) => {
+        let lookup = this.nameLookup(current, parts[i], type);
         // We want to ensure that zero and false are handled properly if the context (falsy flag)
         // needs to have the special handling for these values.
         if (!falsy) {
@@ -513,7 +511,7 @@ JavaScriptCompiler.prototype = {
     this.hash = {values: [], types: [], contexts: [], ids: []};
   },
   popHash: function() {
-    var hash = this.hash;
+    let hash = this.hash;
     this.hash = this.hashes.pop();
 
     if (this.trackIds) {
@@ -575,11 +573,11 @@ JavaScriptCompiler.prototype = {
   //
   // If the helper is not found, `helperMissing` is called.
   invokeHelper: function(paramSize, name, isSimple) {
-    var nonHelper = this.popStack();
-    var helper = this.setupHelper(paramSize, name);
-    var simple = isSimple ? [helper.name, ' || '] : '';
+    let nonHelper = this.popStack(),
+        helper = this.setupHelper(paramSize, name),
+        simple = isSimple ? [helper.name, ' || '] : '';
 
-    var lookup = ['('].concat(simple, nonHelper);
+    let lookup = ['('].concat(simple, nonHelper);
     if (!this.options.strict) {
       lookup.push(' || ', this.aliasable('helpers.helperMissing'));
     }
@@ -596,7 +594,7 @@ JavaScriptCompiler.prototype = {
   // This operation is used when the helper is known to exist,
   // so a `helperMissing` fallback is not required.
   invokeKnownHelper: function(paramSize, name) {
-    var helper = this.setupHelper(paramSize, name);
+    let helper = this.setupHelper(paramSize, name);
     this.push(this.source.functionCall(helper.name, 'call', helper.callParams));
   },
 
@@ -615,14 +613,14 @@ JavaScriptCompiler.prototype = {
   invokeAmbiguous: function(name, helperCall) {
     this.useRegister('helper');
 
-    var nonHelper = this.popStack();
+    let nonHelper = this.popStack();
 
     this.emptyHash();
-    var helper = this.setupHelper(0, name, helperCall);
+    let helper = this.setupHelper(0, name, helperCall);
 
-    var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
+    let helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
 
-    var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')'];
+    let lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')'];
     if (!this.options.strict) {
       lookup[0] = '(helper = ';
       lookup.push(
@@ -647,7 +645,7 @@ JavaScriptCompiler.prototype = {
   // This operation pops off a context, invokes a partial with that context,
   // and pushes the result of the invocation back.
   invokePartial: function(isDynamic, name, indent) {
-    var params = [],
+    let params = [],
         options = this.setupParams(name, 1, params, false);
 
     if (isDynamic) {
@@ -683,7 +681,7 @@ JavaScriptCompiler.prototype = {
   //
   // Pops a value off the stack and assigns it to the current hash
   assignToHash: function(key) {
-    var value = this.popStack(),
+    let value = this.popStack(),
         context,
         type,
         id;
@@ -696,7 +694,7 @@ JavaScriptCompiler.prototype = {
       context = this.popStack();
     }
 
-    var hash = this.hash;
+    let hash = this.hash;
     if (context) {
       hash.contexts[key] = context;
     }
@@ -728,13 +726,13 @@ JavaScriptCompiler.prototype = {
   compiler: JavaScriptCompiler,
 
   compileChildren: function(environment, options) {
-    var children = environment.children, child, compiler;
+    let children = environment.children, child, compiler;
 
-    for (var i = 0, l = children.length; i < l; i++) {
+    for (let i = 0, l = children.length; i < l; i++) {
       child = children[i];
       compiler = new this.compiler();    // eslint-disable-line new-cap
 
-      var index = this.matchExistingProgram(child);
+      let index = this.matchExistingProgram(child);
 
       if (index == null) {
         this.context.programs.push('');     // Placeholder to prevent name conflicts for nested children
@@ -756,8 +754,8 @@ JavaScriptCompiler.prototype = {
     }
   },
   matchExistingProgram: function(child) {
-    for (var i = 0, len = this.context.environments.length; i < len; i++) {
-      var environment = this.context.environments[i];
+    for (let i = 0, len = this.context.environments.length; i < len; i++) {
+      let environment = this.context.environments[i];
       if (environment && environment.equals(child)) {
         return i;
       }
@@ -765,7 +763,7 @@ JavaScriptCompiler.prototype = {
   },
 
   programExpression: function(guid) {
-    var child = this.environment.children[guid],
+    let child = this.environment.children[guid],
         programParams = [child.index, 'data', child.blockParams];
 
     if (this.useBlockParams || this.useDepths) {
@@ -811,7 +809,7 @@ JavaScriptCompiler.prototype = {
   },
 
   replaceStack: function(callback) {
-    var prefix = ['('],
+    let prefix = ['('],
         stack,
         createdStack,
         usedLiteral;
@@ -822,7 +820,7 @@ JavaScriptCompiler.prototype = {
     }
 
     // We want to merge the inline statement into the replacement statement via ','
-    var top = this.popStack(true);
+    let top = this.popStack(true);
 
     if (top instanceof Literal) {
       // Literals do not need to be inlined
@@ -832,13 +830,13 @@ JavaScriptCompiler.prototype = {
     } else {
       // Get or create the current stack name for use by the inline
       createdStack = true;
-      var name = this.incrStack();
+      let name = this.incrStack();
 
       prefix = ['((', this.push(name), ' = ', top, ')'];
       stack = this.topStack();
     }
 
-    var item = callback.call(this, stack);
+    let item = callback.call(this, stack);
 
     if (!usedLiteral) {
       this.popStack();
@@ -858,15 +856,15 @@ JavaScriptCompiler.prototype = {
     return 'stack' + this.stackSlot;
   },
   flushInline: function() {
-    var inlineStack = this.inlineStack;
+    let inlineStack = this.inlineStack;
     this.inlineStack = [];
-    for (var i = 0, len = inlineStack.length; i < len; i++) {
-      var entry = inlineStack[i];
+    for (let i = 0, len = inlineStack.length; i < len; i++) {
+      let entry = inlineStack[i];
       /* istanbul ignore if */
       if (entry instanceof Literal) {
         this.compileStack.push(entry);
       } else {
-        var stack = this.incrStack();
+        let stack = this.incrStack();
         this.pushSource([stack, ' = ', entry, ';']);
         this.compileStack.push(stack);
       }
@@ -877,7 +875,7 @@ JavaScriptCompiler.prototype = {
   },
 
   popStack: function(wrapped) {
-    var inline = this.isInline(),
+    let inline = this.isInline(),
         item = (inline ? this.inlineStack : this.compileStack).pop();
 
     if (!wrapped && (item instanceof Literal)) {
@@ -895,7 +893,7 @@ JavaScriptCompiler.prototype = {
   },
 
   topStack: function() {
-    var stack = (this.isInline() ? this.inlineStack : this.compileStack),
+    let stack = (this.isInline() ? this.inlineStack : this.compileStack),
         item = stack[stack.length - 1];
 
     /* istanbul ignore if */
@@ -923,7 +921,7 @@ JavaScriptCompiler.prototype = {
   },
 
   aliasable: function(name) {
-    var ret = this.aliases[name];
+    let ret = this.aliases[name];
     if (ret) {
       ret.referenceCount++;
       return ret;
@@ -937,9 +935,9 @@ JavaScriptCompiler.prototype = {
   },
 
   setupHelper: function(paramSize, name, blockHelper) {
-    var params = [],
+    let params = [],
         paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);
-    var foundHelper = this.nameLookup('helpers', name, 'helper');
+    let foundHelper = this.nameLookup('helpers', name, 'helper');
 
     return {
       params: params,
@@ -950,7 +948,7 @@ JavaScriptCompiler.prototype = {
   },
 
   setupParams: function(helper, paramSize, params) {
-    var options = {}, contexts = [], types = [], ids = [], param;
+    let options = {}, contexts = [], types = [], ids = [], param;
 
     options.name = this.quotedString(helper);
     options.hash = this.popStack();
@@ -963,7 +961,7 @@ JavaScriptCompiler.prototype = {
       options.hashContexts = this.popStack();
     }
 
-    var inverse = this.popStack(),
+    let inverse = this.popStack(),
         program = this.popStack();
 
     // Avoid setting fn and inverse if neither are set. This allows
@@ -975,7 +973,7 @@ JavaScriptCompiler.prototype = {
 
     // The parameters go on to the stack in order (making sure that they are evaluated in order)
     // so we need to pop them off the stack in reverse order
-    var i = paramSize;
+    let i = paramSize;
     while (i--) {
       param = this.popStack();
       params[i] = param;
@@ -1007,7 +1005,7 @@ JavaScriptCompiler.prototype = {
   },
 
   setupHelperArgs: function(helper, paramSize, params, useRegister) {
-    var options = this.setupParams(helper, paramSize, params, true);
+    let options = this.setupParams(helper, paramSize, params, true);
     options = this.objectLiteral(options);
     if (useRegister) {
       this.useRegister('options');
@@ -1022,7 +1020,7 @@ JavaScriptCompiler.prototype = {
 
 
 (function() {
-  var reservedWords = (
+  const reservedWords = (
     'break else new var' +
     ' case finally return void' +
     ' catch for switch while' +
@@ -1041,9 +1039,9 @@ JavaScriptCompiler.prototype = {
     ' null true false'
   ).split(' ');
 
-  var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
+  const compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
 
-  for (var i = 0, l = reservedWords.length; i < l; i++) {
+  for (let i = 0, l = reservedWords.length; i < l; i++) {
     compilerWords[reservedWords[i]] = true;
   }
 }());
@@ -1053,9 +1051,8 @@ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
 };
 
 function strictLookup(requireTerminal, compiler, parts, type) {
-  var stack = compiler.popStack();
-
-  var i = 0,
+  let stack = compiler.popStack(),
+      i = 0,
       len = parts.length;
   if (requireTerminal) {
     len--;
diff --git a/lib/handlebars/compiler/printer.js b/lib/handlebars/compiler/printer.js
index 5c708a132..691a3567c 100644
--- a/lib/handlebars/compiler/printer.js
+++ b/lib/handlebars/compiler/printer.js
@@ -12,9 +12,9 @@ export function PrintVisitor() {
 PrintVisitor.prototype = new Visitor();
 
 PrintVisitor.prototype.pad = function(string) {
-  var out = '';
+  let out = '';
 
-  for (var i = 0, l = this.padding; i < l; i++) {
+  for (let i = 0, l = this.padding; i < l; i++) {
     out = out + '  ';
   }
 
@@ -23,12 +23,12 @@ PrintVisitor.prototype.pad = function(string) {
 };
 
 PrintVisitor.prototype.Program = function(program) {
-  var out = '',
+  let out = '',
       body = program.body,
       i, l;
 
   if (program.blockParams) {
-    var blockParams = 'BLOCK PARAMS: [';
+    let blockParams = 'BLOCK PARAMS: [';
     for (i = 0, l = program.blockParams.length; i < l; i++) {
        blockParams += ' ' + program.blockParams[i];
     }
@@ -50,7 +50,7 @@ PrintVisitor.prototype.MustacheStatement = function(mustache) {
 };
 
 PrintVisitor.prototype.BlockStatement = function(block) {
-  var out = '';
+  let out = '';
 
   out = out + this.pad('BLOCK:');
   this.padding++;
@@ -75,7 +75,7 @@ PrintVisitor.prototype.BlockStatement = function(block) {
 };
 
 PrintVisitor.prototype.PartialStatement = function(partial) {
-  var content = 'PARTIAL:' + partial.name.original;
+  let content = 'PARTIAL:' + partial.name.original;
   if (partial.params[0]) {
     content += ' ' + this.accept(partial.params[0]);
   }
@@ -94,9 +94,11 @@ PrintVisitor.prototype.CommentStatement = function(comment) {
 };
 
 PrintVisitor.prototype.SubExpression = function(sexpr) {
-  var params = sexpr.params, paramStrings = [], hash;
+  let params = sexpr.params,
+      paramStrings = [],
+      hash;
 
-  for (var i = 0, l = params.length; i < l; i++) {
+  for (let i = 0, l = params.length; i < l; i++) {
     paramStrings.push(this.accept(params[i]));
   }
 
@@ -108,7 +110,7 @@ PrintVisitor.prototype.SubExpression = function(sexpr) {
 };
 
 PrintVisitor.prototype.PathExpression = function(id) {
-  var path = id.parts.join('/');
+  let path = id.parts.join('/');
   return (id.data ? '@' : '') + 'PATH:' + path;
 };
 
@@ -134,10 +136,10 @@ PrintVisitor.prototype.NullLiteral = function() {
 };
 
 PrintVisitor.prototype.Hash = function(hash) {
-  var pairs = hash.pairs;
-  var joinedPairs = [];
+  let pairs = hash.pairs,
+      joinedPairs = [];
 
-  for (var i = 0, l = pairs.length; i < l; i++) {
+  for (let i = 0, l = pairs.length; i < l; i++) {
     joinedPairs.push(this.accept(pairs[i]));
   }
 
diff --git a/lib/handlebars/compiler/visitor.js b/lib/handlebars/compiler/visitor.js
index 692a51194..ba7b3760c 100644
--- a/lib/handlebars/compiler/visitor.js
+++ b/lib/handlebars/compiler/visitor.js
@@ -11,7 +11,7 @@ Visitor.prototype = {
 
   // Visits a given value. If mutating, will replace the value if necessary.
   acceptKey: function(node, name) {
-    var value = this.accept(node[name]);
+    let value = this.accept(node[name]);
     if (this.mutating) {
       // Hacky sanity check:
       if (value && (!value.type || !AST[value.type])) {
@@ -34,7 +34,7 @@ Visitor.prototype = {
   // Traverses a given array. If mutating, empty respnses will be removed
   // for child elements.
   acceptArray: function(array) {
-    for (var i = 0, l = array.length; i < l; i++) {
+    for (let i = 0, l = array.length; i < l; i++) {
       this.acceptKey(array, i);
 
       if (!array[i]) {
@@ -55,7 +55,7 @@ Visitor.prototype = {
     }
     this.current = object;
 
-    var ret = this[object.type](object);
+    let ret = this[object.type](object);
 
     this.current = this.parents.shift();
 
diff --git a/lib/handlebars/compiler/whitespace-control.js b/lib/handlebars/compiler/whitespace-control.js
index aabe45aa8..5b76944dc 100644
--- a/lib/handlebars/compiler/whitespace-control.js
+++ b/lib/handlebars/compiler/whitespace-control.js
@@ -5,19 +5,19 @@ function WhitespaceControl() {
 WhitespaceControl.prototype = new Visitor();
 
 WhitespaceControl.prototype.Program = function(program) {
-  var isRoot = !this.isRootSeen;
+  let isRoot = !this.isRootSeen;
   this.isRootSeen = true;
 
-  var body = program.body;
-  for (var i = 0, l = body.length; i < l; i++) {
-    var current = body[i],
+  let body = program.body;
+  for (let i = 0, l = body.length; i < l; i++) {
+    let current = body[i],
         strip = this.accept(current);
 
     if (!strip) {
       continue;
     }
 
-    var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot),
+    let _isPrevWhitespace = isPrevWhitespace(body, i, isRoot),
         _isNextWhitespace = isNextWhitespace(body, i, isRoot),
 
         openStandalone = strip.openStandalone && _isPrevWhitespace,
@@ -63,7 +63,7 @@ WhitespaceControl.prototype.BlockStatement = function(block) {
   this.accept(block.inverse);
 
   // Find the inverse program that is involed with whitespace stripping.
-  var program = block.program || block.inverse,
+  let program = block.program || block.inverse,
       inverse = block.program && block.inverse,
       firstInverse = inverse,
       lastInverse = inverse;
@@ -77,7 +77,7 @@ WhitespaceControl.prototype.BlockStatement = function(block) {
     }
   }
 
-  var strip = {
+  let strip = {
     open: block.openStrip.open,
     close: block.closeStrip.close,
 
@@ -92,7 +92,7 @@ WhitespaceControl.prototype.BlockStatement = function(block) {
   }
 
   if (inverse) {
-    var inverseStrip = block.inverseStrip;
+    let inverseStrip = block.inverseStrip;
 
     if (inverseStrip.open) {
       omitLeft(program.body, null, true);
@@ -125,7 +125,7 @@ WhitespaceControl.prototype.MustacheStatement = function(mustache) {
 WhitespaceControl.prototype.PartialStatement =
     WhitespaceControl.prototype.CommentStatement = function(node) {
   /* istanbul ignore next */
-  var strip = node.strip || {};
+  let strip = node.strip || {};
   return {
     inlineStandalone: true,
     open: strip.open,
@@ -141,7 +141,7 @@ function isPrevWhitespace(body, i, isRoot) {
 
   // Nodes that end with newlines are considered whitespace (but are special
   // cased for strip operations)
-  var prev = body[i - 1],
+  let prev = body[i - 1],
       sibling = body[i - 2];
   if (!prev) {
     return isRoot;
@@ -156,7 +156,7 @@ function isNextWhitespace(body, i, isRoot) {
     i = -1;
   }
 
-  var next = body[i + 1],
+  let next = body[i + 1],
       sibling = body[i + 2];
   if (!next) {
     return isRoot;
@@ -175,12 +175,12 @@ function isNextWhitespace(body, i, isRoot) {
 // If mulitple is truthy then all whitespace will be stripped out until non-whitespace
 // content is met.
 function omitRight(body, i, multiple) {
-  var current = body[i == null ? 0 : i + 1];
+  let current = body[i == null ? 0 : i + 1];
   if (!current || current.type !== 'ContentStatement' || (!multiple && current.rightStripped)) {
     return;
   }
 
-  var original = current.value;
+  let original = current.value;
   current.value = current.value.replace(multiple ? (/^\s+/) : (/^[ \t]*\r?\n?/), '');
   current.rightStripped = current.value !== original;
 }
@@ -193,13 +193,13 @@ function omitRight(body, i, multiple) {
 // If mulitple is truthy then all whitespace will be stripped out until non-whitespace
 // content is met.
 function omitLeft(body, i, multiple) {
-  var current = body[i == null ? body.length - 1 : i - 1];
+  let current = body[i == null ? body.length - 1 : i - 1];
   if (!current || current.type !== 'ContentStatement' || (!multiple && current.leftStripped)) {
     return;
   }
 
   // We omit the last node if it's whitespace only and not preceeded by a non-content node.
-  var original = current.value;
+  let original = current.value;
   current.value = current.value.replace(multiple ? (/\s+$/) : (/[ \t]+$/), '');
   current.leftStripped = current.value !== original;
   return current.leftStripped;
diff --git a/lib/handlebars/exception.js b/lib/handlebars/exception.js
index 053aea871..46ce18eae 100644
--- a/lib/handlebars/exception.js
+++ b/lib/handlebars/exception.js
@@ -1,8 +1,8 @@
 
-var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
+const errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
 
 function Exception(message, node) {
-  var loc = node && node.loc,
+  let loc = node && node.loc,
       line,
       column;
   if (loc) {
@@ -12,10 +12,10 @@ function Exception(message, node) {
     message += ' - ' + line + ':' + column;
   }
 
-  var tmp = Error.prototype.constructor.call(this, message);
+  let tmp = Error.prototype.constructor.call(this, message);
 
   // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
-  for (var idx = 0; idx < errorProps.length; idx++) {
+  for (let idx = 0; idx < errorProps.length; idx++) {
     this[errorProps[idx]] = tmp[errorProps[idx]];
   }
 
diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js
index f1839aa05..874728fb5 100644
--- a/lib/handlebars/runtime.js
+++ b/lib/handlebars/runtime.js
@@ -3,13 +3,13 @@ import Exception from './exception';
 import { COMPILER_REVISION, REVISION_CHANGES, createFrame } from './base';
 
 export function checkRevision(compilerInfo) {
-  var compilerRevision = compilerInfo && compilerInfo[0] || 1,
-      currentRevision = COMPILER_REVISION;
+  const compilerRevision = compilerInfo && compilerInfo[0] || 1,
+        currentRevision = COMPILER_REVISION;
 
   if (compilerRevision !== currentRevision) {
     if (compilerRevision < currentRevision) {
-      var runtimeVersions = REVISION_CHANGES[currentRevision],
-          compilerVersions = REVISION_CHANGES[compilerRevision];
+      const runtimeVersions = REVISION_CHANGES[currentRevision],
+            compilerVersions = REVISION_CHANGES[compilerRevision];
       throw new Exception('Template was precompiled with an older version of Handlebars than the current runtime. ' +
             'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
     } else {
@@ -41,7 +41,7 @@ export function template(templateSpec, env) {
     }
 
     partial = env.VM.resolvePartial.call(this, partial, context, options);
-    var result = env.VM.invokePartial.call(this, partial, context, options);
+    let result = env.VM.invokePartial.call(this, partial, context, options);
 
     if (result == null && env.compile) {
       options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env);
@@ -49,8 +49,8 @@ export function template(templateSpec, env) {
     }
     if (result != null) {
       if (options.indent) {
-        var lines = result.split('\n');
-        for (var i = 0, l = lines.length; i < l; i++) {
+        let lines = result.split('\n');
+        for (let i = 0, l = lines.length; i < l; i++) {
           if (!lines[i] && i + 1 === l) {
             break;
           }
@@ -66,7 +66,7 @@ export function template(templateSpec, env) {
   }
 
   // Just add water
-  var container = {
+  let container = {
     strict: function(obj, name) {
       if (!(name in obj)) {
         throw new Exception('"' + name + '" not defined in ' + obj);
@@ -74,8 +74,8 @@ export function template(templateSpec, env) {
       return obj[name];
     },
     lookup: function(depths, name) {
-      var len = depths.length;
-      for (var i = 0; i < len; i++) {
+      const len = depths.length;
+      for (let i = 0; i < len; i++) {
         if (depths[i] && depths[i][name] != null) {
           return depths[i][name];
         }
@@ -94,7 +94,7 @@ export function template(templateSpec, env) {
 
     programs: [],
     program: function(i, data, declaredBlockParams, blockParams, depths) {
-      var programWrapper = this.programs[i],
+      let programWrapper = this.programs[i],
           fn = this.fn(i);
       if (data || depths || blockParams || declaredBlockParams) {
         programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths);
@@ -111,7 +111,7 @@ export function template(templateSpec, env) {
       return value;
     },
     merge: function(param, common) {
-      var obj = param || common;
+      let obj = param || common;
 
       if (param && common && (param !== common)) {
         obj = Utils.extend({}, common, param);
@@ -124,15 +124,14 @@ export function template(templateSpec, env) {
     compilerInfo: templateSpec.compiler
   };
 
-  function ret(context, options) {
-    options = options || {};
-    var data = options.data;
+  function ret(context, options = {}) {
+    let data = options.data;
 
     ret._setup(options);
     if (!options.partial && templateSpec.useData) {
       data = initData(context, data);
     }
-    var depths,
+    let depths,
         blockParams = templateSpec.useBlockParams ? [] : undefined;
     if (templateSpec.useDepths) {
       depths = options.depths ? [context].concat(options.depths) : [context];
@@ -169,9 +168,7 @@ export function template(templateSpec, env) {
 }
 
 export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
-  function prog(context, options) {
-    options = options || {};
-
+  function prog(context, options = {}) {
     return fn.call(container,
         context,
         container.helpers, container.partials,
diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js
index 07e9b7784..f474f2918 100644
--- a/lib/handlebars/utils.js
+++ b/lib/handlebars/utils.js
@@ -1,5 +1,5 @@
 /*jshint -W004 */
-var escape = {
+const escape = {
   '&': '&amp;',
   '<': '&lt;',
   '>': '&gt;',
@@ -8,16 +8,16 @@ var escape = {
   '`': '&#x60;'
 };
 
-var badChars = /[&<>"'`]/g;
-var possible = /[&<>"'`]/;
+const badChars = /[&<>"'`]/g,
+      possible = /[&<>"'`]/;
 
 function escapeChar(chr) {
   return escape[chr];
 }
 
 export function extend(obj /* , ...source */) {
-  for (var i = 1; i < arguments.length; i++) {
-    for (var key in arguments[i]) {
+  for (let i = 1; i < arguments.length; i++) {
+    for (let key in arguments[i]) {
       if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
         obj[key] = arguments[i][key];
       }
@@ -27,11 +27,11 @@ export function extend(obj /* , ...source */) {
   return obj;
 }
 
-export var toString = Object.prototype.toString;
+export let toString = Object.prototype.toString;
 
 // Sourced from lodash
 // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
-/*eslint-disable func-style */
+/*eslint-disable func-style, no-var */
 var isFunction = function(value) {
   return typeof value === 'function';
 };
@@ -43,16 +43,16 @@ if (isFunction(/x/)) {
   };
 }
 export var isFunction;
-/*eslint-enable func-style */
+/*eslint-enable func-style, no-var */
 
 /* istanbul ignore next */
-export var isArray = Array.isArray || function(value) {
+export const isArray = Array.isArray || function(value) {
   return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false;
 };
 
 // Older IE versions do not directly support indexOf so we must implement our own, sadly.
 export function indexOf(array, value) {
-  for (var i = 0, len = array.length; i < len; i++) {
+  for (let i = 0, len = array.length; i < len; i++) {
     if (array[i] === value) {
       return i;
     }

From d48e84051360b2c1d40943bfb5ce3cf15273b534 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Mon, 20 Apr 2015 03:10:49 -0500
Subject: [PATCH 16/17] Update release notes

---
 release-notes.md | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/release-notes.md b/release-notes.md
index 1d6787eee..b41226161 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -2,7 +2,18 @@
 
 ## Development
 
-[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.1...master)
+[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.2...master)
+
+## v3.0.2 - April 20th, 2015
+- [#998](https://github.com/wycats/handlebars.js/pull/998) - Add full support for es6 ([@kpdecker](https://api.github.com/users/kpdecker))
+- [#994](https://github.com/wycats/handlebars.js/issues/994) - Access Handlebars.Visitor in browser ([@tamlyn](https://api.github.com/users/tamlyn))
+- [#990](https://github.com/wycats/handlebars.js/issues/990) - Allow passing null/undefined literals subexpressions ([@blimmer](https://api.github.com/users/blimmer))
+- [#989](https://github.com/wycats/handlebars.js/issues/989) - Source-map error with requirejs ([@SteppeEagle](https://api.github.com/users/SteppeEagle))
+- [#967](https://github.com/wycats/handlebars.js/issues/967) - can't access "this" property  ([@75lb](https://api.github.com/users/75lb))
+- Use captureStackTrace for error handler - a009a97
+- Ignore branches tested without coverage monitoring - 37a664b
+
+[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.1...v3.0.2)
 
 ## v3.0.1 - March 24th, 2015
 - [#984](https://github.com/wycats/handlebars.js/pull/984) - Adding documentation for passing arguments into partials ([@johneke](https://api.github.com/users/johneke))

From 2f0b86665f6080c065d67182ccfdca2ce6f243fa Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Mon, 20 Apr 2015 03:11:12 -0500
Subject: [PATCH 17/17] v3.0.2

---
 components/bower.json           | 2 +-
 components/handlebars.js.nuspec | 2 +-
 package.json                    | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/components/bower.json b/components/bower.json
index 0726c8468..7163ae75b 100644
--- a/components/bower.json
+++ b/components/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "handlebars",
-  "version": "3.0.1",
+  "version": "3.0.2",
   "main": "handlebars.js",
   "dependencies": {}
 }
diff --git a/components/handlebars.js.nuspec b/components/handlebars.js.nuspec
index 9525fcf4c..20e3840b7 100644
--- a/components/handlebars.js.nuspec
+++ b/components/handlebars.js.nuspec
@@ -2,7 +2,7 @@
 <package>
 	<metadata>
 		<id>handlebars.js</id>
-		<version>3.0.1</version>
+		<version>3.0.2</version>
 		<authors>handlebars.js Authors</authors>
 		<licenseUrl>https://github.com/wycats/handlebars.js/blob/master/LICENSE</licenseUrl>
 		<projectUrl>https://github.com/wycats/handlebars.js/</projectUrl>
diff --git a/package.json b/package.json
index b23b783dd..bc4be6894 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "handlebars",
   "barename": "handlebars",
-  "version": "3.0.1",
+  "version": "3.0.2",
   "description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration",
   "homepage": "http://www.handlebarsjs.com/",
   "keywords": [
