From 3696d23752a86991a623392b29881965779eb301 Mon Sep 17 00:00:00 2001
From: Nik Nyby <nnyby@columbia.edu>
Date: Fri, 4 Sep 2015 15:47:52 -0400
Subject: [PATCH 1/9] grammar fixes in 4.0.0 release notes

---
 release-notes.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/release-notes.md b/release-notes.md
index 822cb80fa..b2547298c 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -50,7 +50,7 @@
 - Fix location information for programs - [93faffa](https://github.com/wycats/handlebars.js/commit/93faffa)
 
 Compatibility notes:
-- Depthed paths are now conditional pushed on to the stack. If the helper uses the same context, then a new stack is not created. This leads to behavior the better matches expectations for helpers like `if` that do not seem to alter the context. Any instances of `../` in templates will need to be checked for the correct behavior under 4.0.0. In general templates will either reduce the number of `../` instances or leave them as is. See [#1028](https://github.com/wycats/handlebars.js/issues/1028).
+- Depthed paths are now conditionally pushed on to the stack. If the helper uses the same context, then a new stack is not created. This leads to behavior that better matches expectations for helpers like `if` that do not seem to alter the context. Any instances of `../` in templates will need to be checked for the correct behavior under 4.0.0. In general templates will either reduce the number of `../` instances or leave them as is. See [#1028](https://github.com/wycats/handlebars.js/issues/1028).
 - The `=` character is now HTML escaped. This closes a potential exploit case when using unquoted attributes, i.e. `<div foo={{bar}}>`. In general it's recommended that attributes always be quoted when their values are generated from a mustache to avoid any potential exploit surfaces.
 - AST constructors have been dropped in favor of plain old javascript objects
 - The runtime version has been increased. Precompiled templates will need to use runtime of at least 4.0.0.

From efad390ffcfa3288c0f0e3763a9cc368295e8575 Mon Sep 17 00:00:00 2001
From: Nik Nyby <nnyby@columbia.edu>
Date: Fri, 4 Sep 2015 15:53:31 -0400
Subject: [PATCH 2/9] fix typo in release notes

---
 release-notes.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/release-notes.md b/release-notes.md
index 822cb80fa..0990c508a 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -238,7 +238,7 @@ Compatibility notes:
   - INTEGER -> NUMBER
   - Additional PartialNode hash parameter
   - New RawBlockNode type
-- Data frames now have a `_parent` field. This is internal but is enumerable for performance/compatability reasons.
+- Data frames now have a `_parent` field. This is internal but is enumerable for performance/compatibility reasons.
 
 [Commits](https://github.com/wycats/handlebars.js/compare/v1.3.0...v2.0.0-alpha.1)
 

From 641fe335df78c436aecf5e7173fde529f72ac2f8 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Wed, 16 Sep 2015 15:51:31 -0500
Subject: [PATCH 3/9] Update travis to test node 0.12 and 4.0.0

---
 .travis.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index b9ecde273..c6e2c8439 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,11 +13,12 @@ env:
   - secure: Nm4AgSfsgNB21kgKrF9Tl7qVZU8YYREhouQunFracTcZZh2NZ2XH5aHuSiXCj88B13Cr/jGbJKsZ4T3QS3wWYtz6lkyVOx3H3iI+TMtqhD9RM3a7A4O+4vVN8IioB2YjhEu0OKjwgX5gp+0uF+pLEi7Hpj6fupD3AbbL5uYcKg8=
 matrix:
   include:
-  - node_js: '0.10'
+  - node_js: '0.12'
     env:
     - PUBLISH=true
     - secure: pLTzghtVll9yGKJI0AaB0uI8GypfWxLTaIB0ZL8//yN3nAEIKMhf/RRilYTsn/rKj2NUa7vt2edYILi3lttOUlCBOwTc9amiRms1W8Lwr/3IdWPeBLvLuH1zNJRm2lBAwU4LBSqaOwhGaxOQr6KHTnWudhNhgOucxpZfvfI/dFw=
     - secure: yERYCf7AwL11D9uMtacly/THGV8BlzsMmrt+iQVvGA3GaY6QMmfYqf6P6cCH98sH5etd1Y+1e6YrPeMjqI6lyRllT7FptoyOdHulazQe86VQN4sc0EpqMlH088kB7gGjTut9Z+X9ViooT5XEh9WA5jXEI9pXhQJNoIHkWPuwGuY=
+  - node_js: '4.0.0'
 cache:
   directories:
   - node_modules

From 08781798f564a68abee11c74e2b98272657b2a56 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Wed, 16 Sep 2015 16:11:56 -0500
Subject: [PATCH 4/9] Allow for escaped ] characters in [] IDs

Allows for ] literal characters to be used within [] IDs by prefixing them with the \ character. `\` literal at the end of the  may be referenced by the `\\` sequence if conflicting. Under most circumstances the `\\` sequence will continue to work.

Potentially breaking change for users of [] ids that have `\\` anywhere in the id or `\` at the end of the id.

Fixes #1092
---
 spec/parser.js    | 6 ++++++
 spec/tokenizer.js | 5 +++++
 src/handlebars.l  | 2 +-
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/spec/parser.js b/spec/parser.js
index 3b7e3e45f..4527d19c1 100644
--- a/spec/parser.js
+++ b/spec/parser.js
@@ -39,6 +39,12 @@ describe('parser', function() {
   it('parses mustaches with - in a path', function() {
     equals(astFor('{{foo-bar}}'), '{{ PATH:foo-bar [] }}\n');
   });
+  it('parses mustaches with escaped [] in a path', function() {
+    equals(astFor('{{[foo[\\]]}}'), '{{ PATH:foo[] [] }}\n');
+  });
+  it('parses escaped \\\\ in path', function() {
+    equals(astFor('{{[foo\\\\]}}'), '{{ PATH:foo\\ [] }}\n');
+  });
 
   it('parses mustaches with parameters', function() {
     equals(astFor('{{foo bar}}'), '{{ PATH:foo [PATH:bar] }}\n');
diff --git a/spec/tokenizer.js b/spec/tokenizer.js
index dc077ce72..428804e01 100644
--- a/spec/tokenizer.js
+++ b/spec/tokenizer.js
@@ -146,6 +146,11 @@ describe('Tokenizer', function() {
     shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE', 'OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
   });
 
+  it('allows escaped literals in []', function() {
+    var result = tokenize('{{foo.[bar\\]]}}');
+    shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']);
+  });
+
   it('tokenizes {{.}} as OPEN ID CLOSE', function() {
     var result = tokenize('{{.}}');
     shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']);
diff --git a/src/handlebars.l b/src/handlebars.l
index 4c3c30421..e9de1029b 100644
--- a/src/handlebars.l
+++ b/src/handlebars.l
@@ -120,7 +120,7 @@ ID    [^\s!"#%-,\.\/;->@\[-\^`\{-~]+/{LOOKAHEAD}
 
 <mu>{ID}                         return 'ID';
 
-<mu>'['[^\]]*']'                 return 'ID';
+<mu>'['('\\]'|[^\]])*']'         yytext = yytext.replace(/\\([\\\]])/g,'$1'); return 'ID';
 <mu>.                            return 'INVALID';
 
 <INITIAL,mu><<EOF>>              return 'EOF';

From fffb5a985f8ff7cd75f2c16b37b69f7ddd3ba9a0 Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Wed, 23 Sep 2015 21:17:57 -0500
Subject: [PATCH 5/9] Fix iteration over undefined values

Allow for iteration on undefined values, but special case undefined and null to prevent rendering errors when not running in strict mode.

Fixes #1093
---
 lib/handlebars/compiler/javascript-compiler.js |  5 +++--
 lib/handlebars/helpers/each.js                 | 10 +++-------
 spec/regressions.js                            | 18 ++++++++++++++++++
 3 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js
index d0f206c58..bd48e9b1c 100644
--- a/lib/handlebars/compiler/javascript-compiler.js
+++ b/lib/handlebars/compiler/javascript-compiler.js
@@ -984,13 +984,14 @@ JavaScriptCompiler.prototype = {
   setupHelper: function(paramSize, name, blockHelper) {
     let params = [],
         paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);
-    let foundHelper = this.nameLookup('helpers', name, 'helper');
+    let foundHelper = this.nameLookup('helpers', name, 'helper'),
+        callContext = this.aliasable(`${this.contextName(0)} != null ? ${this.contextName(0)} : {}`);
 
     return {
       params: params,
       paramsInit: paramsInit,
       name: foundHelper,
-      callParams: [this.contextName(0)].concat(params)
+      callParams: [callContext].concat(params)
     };
   },
 
diff --git a/lib/handlebars/helpers/each.js b/lib/handlebars/helpers/each.js
index 9b1629b40..fb11903c8 100644
--- a/lib/handlebars/helpers/each.js
+++ b/lib/handlebars/helpers/each.js
@@ -25,12 +25,6 @@ export default function(instance) {
     }
 
     function execIteration(field, index, last) {
-      // Don't iterate over undefined values since we can't execute blocks against them
-      // in non-strict (js) mode.
-      if (context[field] == null) {
-        return;
-      }
-
       if (data) {
         data.key = field;
         data.index = index;
@@ -51,7 +45,9 @@ export default function(instance) {
     if (context && typeof context === 'object') {
       if (isArray(context)) {
         for (let j = context.length; i < j; i++) {
-          execIteration(i, i, i === context.length - 1);
+          if (i in context) {
+            execIteration(i, i, i === context.length - 1);
+          }
         }
       } else {
         let priorKey;
diff --git a/spec/regressions.js b/spec/regressions.js
index cca126e37..931fc4b65 100644
--- a/spec/regressions.js
+++ b/spec/regressions.js
@@ -204,6 +204,24 @@ describe('Regressions', function() {
     shouldCompileTo('{{#each array}}{{@index}}{{.}}{{/each}}', {array: array}, '1foo3bar');
   });
 
+  it('GH-1093: Undefined helper context', function() {
+    var obj = {foo: undefined, bar: 'bat'};
+    var helpers = {
+      helper: function() {
+        // It's valid to execute a block against an undefined context, but
+        // helpers can not do so, so we expect to have an empty object here;
+        for (var name in this) {
+          if (this.hasOwnProperty(name)) {
+            return 'found';
+          }
+        }
+        return 'not';
+      }
+    };
+
+    shouldCompileTo('{{#each obj}}{{{helper}}}{{.}}{{/each}}', [{obj: obj}, helpers], 'notfoundbat');
+  });
+
   it('should support multiple levels of inline partials', function() {
     var string = '{{#> layout}}{{#*inline "subcontent"}}subcontent{{/inline}}{{/layout}}';
     var partials = {

From 861d6f7b8d8149657c5396ed6b2e2930294edd4e Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Wed, 23 Sep 2015 21:59:49 -0500
Subject: [PATCH 6/9] Fix tests under IE

---
 lib/handlebars/logger.js |  4 +++-
 spec/env/common.js       | 10 +++++-----
 spec/index.html          |  1 +
 spec/regressions.js      |  3 ++-
 4 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/lib/handlebars/logger.js b/lib/handlebars/logger.js
index 1d583ddb9..1ab0051f5 100644
--- a/lib/handlebars/logger.js
+++ b/lib/handlebars/logger.js
@@ -1,3 +1,5 @@
+import {indexOf} from './utils';
+
 let logger = {
   methodMap: ['debug', 'info', 'warn', 'error'],
   level: 'info',
@@ -5,7 +7,7 @@ let logger = {
   // Maps a given level value to the `methodMap` indexes above.
   lookupLevel: function(level) {
     if (typeof level === 'string') {
-      let levelMap = logger.methodMap.indexOf(level.toLowerCase());
+      let levelMap = indexOf(logger.methodMap, level.toLowerCase());
       if (levelMap >= 0) {
         level = levelMap;
       } else {
diff --git a/spec/env/common.js b/spec/env/common.js
index 2a24db20f..e37805261 100644
--- a/spec/env/common.js
+++ b/spec/env/common.js
@@ -61,12 +61,12 @@ global.shouldThrow = function(callback, type, msg) {
   try {
     callback();
     failed = true;
-  } catch (err) {
-    if (type && !(err instanceof type)) {
-      throw new AssertError('Type failure: ' + err);
+  } catch (caught) {
+    if (type && !(caught instanceof type)) {
+      throw new AssertError('Type failure: ' + caught);
     }
-    if (msg && !(msg.test ? msg.test(err.message) : msg === err.message)) {
-      throw new AssertError('Throw mismatch: Expected ' + err.message + ' to match ' + msg + '\n\n' + err.stack, shouldThrow);
+    if (msg && !(msg.test ? msg.test(caught.message) : msg === caught.message)) {
+      throw new AssertError('Throw mismatch: Expected ' + caught.message + ' to match ' + msg + '\n\n' + caught.stack, shouldThrow);
     }
   }
   if (failed) {
diff --git a/spec/index.html b/spec/index.html
index 348ae89d6..5db2146ad 100644
--- a/spec/index.html
+++ b/spec/index.html
@@ -1,3 +1,4 @@
+<!doctype html>
 <html>
   <head>
     <title>Mocha</title>
diff --git a/spec/regressions.js b/spec/regressions.js
index 931fc4b65..bd0a111e8 100644
--- a/spec/regressions.js
+++ b/spec/regressions.js
@@ -215,7 +215,8 @@ describe('Regressions', function() {
             return 'found';
           }
         }
-        return 'not';
+        // And to make IE happy, check for the known string as length is not enumerated.
+        return (this == 'bat' ? 'found' : 'not');
       }
     };
 

From 94c840b6edd426947e1cafa1ff6d6b90e63dbb9a Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Wed, 23 Sep 2015 22:08:59 -0500
Subject: [PATCH 7/9] Create data frame for @partial-block

Fixes #1099
---
 lib/handlebars/runtime.js | 1 +
 spec/regressions.js       | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js
index 52d9b9483..b47d9615d 100644
--- a/lib/handlebars/runtime.js
+++ b/lib/handlebars/runtime.js
@@ -230,6 +230,7 @@ export function invokePartial(partial, context, options) {
 
   let partialBlock;
   if (options.fn && options.fn !== noop) {
+    options.data = createFrame(options.data);
     partialBlock = options.data['partial-block'] = options.fn;
 
     if (partialBlock.partials) {
diff --git a/spec/regressions.js b/spec/regressions.js
index bd0a111e8..83765a223 100644
--- a/spec/regressions.js
+++ b/spec/regressions.js
@@ -239,4 +239,12 @@ describe('Regressions', function() {
     };
     shouldCompileToWithPartials(string, [{}, {}, partials], true, 'doctypelayoutsubcontent');
   });
+  it('GH-1099: should support greater than 3 nested levels of inline partials', function() {
+    var string = '{{#> layout}}Outer{{/layout}}';
+    var partials = {
+      layout: '{{#> inner}}Inner{{/inner}}{{> @partial-block }}',
+      inner: ''
+    };
+    shouldCompileToWithPartials(string, [{}, {}, partials], true, 'Outer');
+  });
 });

From bf091777a9d2eff862b445c081c67ce1fae4896d Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Wed, 23 Sep 2015 22:40:45 -0500
Subject: [PATCH 8/9] Update release notes

---
 release-notes.md | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/release-notes.md b/release-notes.md
index 81a36002f..9736ad093 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -2,7 +2,20 @@
 
 ## Development
 
-[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.2...master)
+[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.3...master)
+
+## v4.0.3 - September 23rd, 2015
+- [#1099](https://github.com/wycats/handlebars.js/issues/1099) - @partial-block is overridden ([@btmorex](https://api.github.com/users/btmorex))
+- [#1093](https://github.com/wycats/handlebars.js/issues/1093) - #each skips iteration on undefined values ([@florianpilz](https://api.github.com/users/florianpilz))
+- [#1092](https://github.com/wycats/handlebars.js/issues/1092) - Square braces in key name ([@distantnative](https://api.github.com/users/distantnative))
+- [#1091](https://github.com/wycats/handlebars.js/pull/1091) - fix typo in release notes ([@nikolas](https://api.github.com/users/nikolas))
+- [#1090](https://github.com/wycats/handlebars.js/pull/1090) - grammar fixes in 4.0.0 release notes ([@nikolas](https://api.github.com/users/nikolas))
+
+Compatibility notes:
+- `each` iteration with `undefined` values has been restored to the 3.0 behaviors. Helper calls with undefined context values will now execute against an arbitrary empty object to avoid executing against global object in non-strict mode.
+- `]` can now be included in `[]` wrapped identifiers by escaping with `\`. Any `[]` identifiers that include `\` will now have to properly escape these values.
+
+[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.2...v4.0.3)
 
 ## v4.0.2 - September 4th, 2015
 - [#1089](https://github.com/wycats/handlebars.js/issues/1089) - "Failover content" not working in multiple levels of inline partials ([@michaellopez](https://api.github.com/users/michaellopez))

From 9365b8290070f34bf797c836aed4335ce6a4094f Mon Sep 17 00:00:00 2001
From: kpdecker <kpdecker@gmail.com>
Date: Wed, 23 Sep 2015 22:41:14 -0500
Subject: [PATCH 9/9] v4.0.3

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

diff --git a/components/bower.json b/components/bower.json
index 0f54800af..5751938d6 100644
--- a/components/bower.json
+++ b/components/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "handlebars",
-  "version": "4.0.2",
+  "version": "4.0.3",
   "main": "handlebars.js",
   "license": "MIT",
   "dependencies": {}
diff --git a/components/handlebars.js.nuspec b/components/handlebars.js.nuspec
index ebdb8932c..56899417c 100644
--- a/components/handlebars.js.nuspec
+++ b/components/handlebars.js.nuspec
@@ -2,7 +2,7 @@
 <package>
 	<metadata>
 		<id>handlebars.js</id>
-		<version>4.0.2</version>
+		<version>4.0.3</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/lib/handlebars/base.js b/lib/handlebars/base.js
index 53469eb2d..67fcc206c 100644
--- a/lib/handlebars/base.js
+++ b/lib/handlebars/base.js
@@ -4,7 +4,7 @@ import {registerDefaultHelpers} from './helpers';
 import {registerDefaultDecorators} from './decorators';
 import logger from './logger';
 
-export const VERSION = '4.0.2';
+export const VERSION = '4.0.3';
 export const COMPILER_REVISION = 7;
 
 export const REVISION_CHANGES = {
diff --git a/package.json b/package.json
index 970d13e4c..9d6c0b66a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "handlebars",
   "barename": "handlebars",
-  "version": "4.0.2",
+  "version": "4.0.3",
   "description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration",
   "homepage": "http://www.handlebarsjs.com/",
   "keywords": [
