From 3696d23752a86991a623392b29881965779eb301 Mon Sep 17 00:00:00 2001 From: Nik Nyby 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. `
`. 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 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 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 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} {ID} return 'ID'; -'['[^\]]*']' return 'ID'; +'['('\\]'|[^\]])*']' yytext = yytext.replace(/\\([\\\]])/g,'$1'); return 'ID'; . return 'INVALID'; <> return 'EOF'; From fffb5a985f8ff7cd75f2c16b37b69f7ddd3ba9a0 Mon Sep 17 00:00:00 2001 From: kpdecker 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 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 @@ + Mocha 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 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 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 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 @@ handlebars.js - 4.0.2 + 4.0.3 handlebars.js Authors https://github.com/wycats/handlebars.js/blob/master/LICENSE https://github.com/wycats/handlebars.js/ 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": [