From c393c815619bac0b4fee44a88323c09be48b6318 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 15:27:56 -0600 Subject: [PATCH 01/29] Relax depth check for context push Fixes #1135 --- lib/handlebars/runtime.js | 4 ++-- spec/regressions.js | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index b47d9615..70493ce2 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -140,7 +140,7 @@ export function template(templateSpec, env) { blockParams = templateSpec.useBlockParams ? [] : undefined; if (templateSpec.useDepths) { if (options.depths) { - depths = context !== options.depths[0] ? [context].concat(options.depths) : options.depths; + depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths; } else { depths = [context]; } @@ -187,7 +187,7 @@ export function template(templateSpec, env) { export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) { function prog(context, options = {}) { let currentDepths = depths; - if (depths && context !== depths[0]) { + if (depths && context != depths[0]) { currentDepths = [context].concat(depths); } diff --git a/spec/regressions.js b/spec/regressions.js index 83765a22..9bd00d94 100644 --- a/spec/regressions.js +++ b/spec/regressions.js @@ -247,4 +247,27 @@ describe('Regressions', function() { }; shouldCompileToWithPartials(string, [{}, {}, partials], true, 'Outer'); }); + + it('GH-1135 : Context handling within each iteration', function() { + var obj = {array: [1], name: 'John'}; + var helpers = { + myif: function(conditional, options) { + if (conditional) { + return options.fn(this); + } else { + return options.inverse(this); + } + } + }; + + shouldCompileTo(` + {{#each array}} + 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}} + 2. MYIF: {{#myif true}}{{../name}}={{../../name}}={{../../../name}}{{/myif}} + {{/each}} + `, [obj, helpers], ` + 1. IF: John-- + 2. MYIF: John== + `); + }); }); From 6c9f98c0252ec42bb9ca8e6584fd45ffd0809acf Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 15:34:06 -0600 Subject: [PATCH 02/29] Update build for modern node versions --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c6e2c843..00c8b001 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,12 +13,12 @@ env: - secure: Nm4AgSfsgNB21kgKrF9Tl7qVZU8YYREhouQunFracTcZZh2NZ2XH5aHuSiXCj88B13Cr/jGbJKsZ4T3QS3wWYtz6lkyVOx3H3iI+TMtqhD9RM3a7A4O+4vVN8IioB2YjhEu0OKjwgX5gp+0uF+pLEi7Hpj6fupD3AbbL5uYcKg8= matrix: include: - - node_js: '0.12' + - node_js: '5' env: - PUBLISH=true - secure: pLTzghtVll9yGKJI0AaB0uI8GypfWxLTaIB0ZL8//yN3nAEIKMhf/RRilYTsn/rKj2NUa7vt2edYILi3lttOUlCBOwTc9amiRms1W8Lwr/3IdWPeBLvLuH1zNJRm2lBAwU4LBSqaOwhGaxOQr6KHTnWudhNhgOucxpZfvfI/dFw= - secure: yERYCf7AwL11D9uMtacly/THGV8BlzsMmrt+iQVvGA3GaY6QMmfYqf6P6cCH98sH5etd1Y+1e6YrPeMjqI6lyRllT7FptoyOdHulazQe86VQN4sc0EpqMlH088kB7gGjTut9Z+X9ViooT5XEh9WA5jXEI9pXhQJNoIHkWPuwGuY= - - node_js: '4.0.0' + - node_js: '4' cache: directories: - node_modules From 20c965cd65d646948d76522e4f20d38cd39762a3 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 16:07:52 -0600 Subject: [PATCH 03/29] Fix throw when creating exception object in Safari https://github.com/jquery/esprima/issues/1290 --- lib/handlebars/exception.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/handlebars/exception.js b/lib/handlebars/exception.js index 52499c0c..24734d47 100644 --- a/lib/handlebars/exception.js +++ b/lib/handlebars/exception.js @@ -12,7 +12,7 @@ function Exception(message, node) { message += ' - ' + line + ':' + column; } - let tmp = Error.prototype.constructor.call(this, message); + let tmp = Error.prototype.constructor.call(this, message, loc && loc.source, line); // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. for (let idx = 0; idx < errorProps.length; idx++) { @@ -24,9 +24,19 @@ function Exception(message, node) { Error.captureStackTrace(this, Exception); } - if (loc) { - this.lineNumber = line; - this.column = column; + try { + if (loc) { + this.lineNumber = line; + + // Work around issue under safari where we can't directly set the column value + if (Object.defineProperty) { + Object.defineProperty(this, 'column', {value: column}); + } else { + this.column = column; + } + } + } catch (nop) { + /* Ignore if the browser is very particular */ } } From 32d6363841740ba869c3b2e3d15bb1a2eaaf0c1f Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 16:14:17 -0600 Subject: [PATCH 04/29] Exclude coverage check in exception conditional --- lib/handlebars/exception.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/handlebars/exception.js b/lib/handlebars/exception.js index 24734d47..af675d9c 100644 --- a/lib/handlebars/exception.js +++ b/lib/handlebars/exception.js @@ -29,6 +29,7 @@ function Exception(message, node) { this.lineNumber = line; // Work around issue under safari where we can't directly set the column value + /* istanbul ignore next */ if (Object.defineProperty) { Object.defineProperty(this, 'column', {value: column}); } else { From fee23342b14c04802b2def6550793070d425a519 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 16:26:48 -0600 Subject: [PATCH 05/29] Update target browser test versions --- Gruntfile.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index fd76518a..97cfff06 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -166,11 +166,10 @@ module.exports = function(grunt) { browsers: [ {browserName: 'chrome'}, {browserName: 'firefox', platform: 'Linux'}, - {browserName: 'safari', version: 7, platform: 'OS X 10.9'}, - {browserName: 'safari', version: 6, platform: 'OS X 10.8'}, + {browserName: 'safari', version: 9, platform: 'OS X 10.11'}, + {browserName: 'safari', version: 8, platform: 'OS X 10.10'}, {browserName: 'internet explorer', version: 11, platform: 'Windows 8.1'}, - {browserName: 'internet explorer', version: 10, platform: 'Windows 8'}, - {browserName: 'internet explorer', version: 9, platform: 'Windows 7'} + {browserName: 'internet explorer', version: 10, platform: 'Windows 8'} ] } }, From 400916c225236d425c27a546a0d2d11b43f437f0 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 17:09:24 -0600 Subject: [PATCH 06/29] Avoid error in older browsers in test The tests are run through the transpiler and just reverting the user of template literal is easier than adding transpiler to the test stack. --- spec/regressions.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/spec/regressions.js b/spec/regressions.js index 9bd00d94..a1eec2f1 100644 --- a/spec/regressions.js +++ b/spec/regressions.js @@ -260,14 +260,12 @@ describe('Regressions', function() { } }; - shouldCompileTo(` - {{#each array}} - 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}} - 2. MYIF: {{#myif true}}{{../name}}={{../../name}}={{../../../name}}{{/myif}} - {{/each}} - `, [obj, helpers], ` - 1. IF: John-- - 2. MYIF: John== - `); + shouldCompileTo( + '{{#each array}}\n' + + ' 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}}\n' + + ' 2. MYIF: {{#myif true}}{{../name}}={{../../name}}={{../../../name}}{{/myif}}\n' + + '{{/each}}', [obj, helpers], + ' 1. IF: John--\n' + + ' 2. MYIF: John==\n'); }); }); From 8fc16367b0ecba86bb61d02a68e255acc3d6a51e Mon Sep 17 00:00:00 2001 From: Ryan Lewis Date: Sun, 13 Dec 2015 20:40:50 -0800 Subject: [PATCH 07/29] Add documentation for running tests to contributing.md lawnsea: this contains the changes from 8a9c79b --- CONTRIBUTING.md | 19 +++++++++++++++++++ spec/mustache | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 79db3ba8..08147607 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,6 +42,25 @@ The `grunt dev` implements watching for tests and allows for in browser testing If you notice any problems, please report them to the GitHub issue tracker at [http://github.com/wycats/handlebars.js/issues](http://github.com/wycats/handlebars.js/issues). +##Running Tests + +To run tests locally, first install all dependencies. +```sh +npm install +``` + +Clone the mustache specs into the spec/mustache folder. +```sh +cd spec +rm -r mustache +git clone https://github.com/mustache/spec.git mustache +``` + +From the root directory, run the tests. +```sh +npm test +``` + ## Ember testing The current ember distribution should be tested as part of the handlebars release process. This requires building the `handlebars-source` gem locally and then executing the ember test script. diff --git a/spec/mustache b/spec/mustache index 72233f3f..83b07216 160000 --- a/spec/mustache +++ b/spec/mustache @@ -1 +1 @@ -Subproject commit 72233f3ffda9e33915fd3022d0a9ebbcce265acd +Subproject commit 83b0721610a4e11832e83df19c73ace3289972b9 From 8c198744972054d8f92697530eee02ebd01511fe Mon Sep 17 00:00:00 2001 From: kpdecker Date: Mon, 14 Dec 2015 02:19:03 -0600 Subject: [PATCH 08/29] Drop extra Error params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was causing a difficult to diagnose failure under IE and doesn’t give us enough value to justify the change. --- lib/handlebars/exception.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/handlebars/exception.js b/lib/handlebars/exception.js index af675d9c..08ae531a 100644 --- a/lib/handlebars/exception.js +++ b/lib/handlebars/exception.js @@ -12,7 +12,7 @@ function Exception(message, node) { message += ' - ' + line + ':' + column; } - let tmp = Error.prototype.constructor.call(this, message, loc && loc.source, line); + 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 (let idx = 0; idx < errorProps.length; idx++) { From 577b760b50a1bdfe050578568a5c93b0c8a57e56 Mon Sep 17 00:00:00 2001 From: "Anders D. Johnson" Date: Wed, 23 Dec 2015 15:28:46 -0600 Subject: [PATCH 09/29] Fix typos on decorators-api.md. --- docs/decorators-api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/decorators-api.md b/docs/decorators-api.md index e14a33ff..566c7eb8 100644 --- a/docs/decorators-api.md +++ b/docs/decorators-api.md @@ -2,9 +2,9 @@ Decorators allow for blocks to be annotated with metadata or wrapped in functionality prior to execution of the block. This may be used to communicate with the containing helper or to setup a particular state in the system prior to running the block. -Decorators are registered through similar methods as helpers, `registerDecorators` and `unregisterDecorators`. These can then be referenced via the friendly name in the template using the `{{* decorator}}` and `{{#* decorator}}{/decorator}}` syntaxes. These syntaxs are derivitives of the normal mustache syntax and as such have all of the same argument and whitespace behaviors. +Decorators are registered through similar methods as helpers, `registerDecorators` and `unregisterDecorators`. These can then be referenced via the friendly name in the template using the `{{* decorator}}` and `{{#* decorator}}{/decorator}}` syntaxes. These syntaxes are derivatives of the normal mustache syntax and as such have all of the same argument and whitespace behaviors. -Decorators are executed when the block program is instantiated and are passed `(program, props, container, context, data, blockParams, depths)` +Decorators are executed when the block program is instantiated and are passed `(program, props, container, context, data, blockParams, depths)`. - `program`: The block to wrap - `props`: Object used to set metadata on the final function. Any values set on this object will be set on the function, regardless of if the original function is replaced or not. Metadata should be applied using this object as values applied to `program` may be masked by subsequent decorators that may wrap `program`. From 959ee557b02e5e424c37af31de43a81bf2453034 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 24 Dec 2015 09:44:36 -0600 Subject: [PATCH 10/29] Update jsfiddle to point to latest --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 08147607..d77d107a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,4 +96,4 @@ After this point the handlebars site needs to be updated to point to the new ver [generator-release]: https://github.com/walmartlabs/generator-release [pull-request]: https://github.com/wycats/handlebars.js/pull/new/master [issue]: https://github.com/wycats/handlebars.js/issues/new -[jsfiddle]: http://jsfiddle.net/9D88g/46/ +[jsfiddle]: https://jsfiddle.net/9D88g/47/ From 6272c150740e9d47e135643a75a2d1ace23add9e Mon Sep 17 00:00:00 2001 From: Tim Wang Date: Wed, 6 Jan 2016 10:47:29 +0800 Subject: [PATCH 11/29] Update license date --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 4effa391..307ebc1c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2011-2015 by Yehuda Katz +Copyright (C) 2011-2016 by Yehuda Katz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 1379e8f50c63d78d1faff29134eeecc756971b2d Mon Sep 17 00:00:00 2001 From: Paul Falgout Date: Tue, 19 Jan 2016 16:21:50 -0600 Subject: [PATCH 12/29] Contributing doc fix: failing thats -> failing tests --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d77d107a..1ea24664 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ Please see our [FAQ](https://github.com/wycats/handlebars.js/blob/master/FAQ.md) Should you run into other issues with the project, please don't hesitate to let us know by filing an [issue][issue]! In general we are going to ask for an example of the problem failing, which can be as simple as a jsfiddle/jsbin/etc. We've put together a jsfiddle [template][jsfiddle] to ease this. (We will keep this link up to date as new releases occur, so feel free to check back here) -Pull requests containing only failing thats demonstrating the issue are welcomed and this also helps ensure that your issue won't regress in the future once it's fixed. +Pull requests containing only failing tests demonstrating the issue are welcomed and this also helps ensure that your issue won't regress in the future once it's fixed. Documentation issues on the handlebarsjs.com site should be reported on [handlebars-site](https://github.com/wycats/handlebars-site). From 45e14b7b4557255709e0ca3a07f645ecf0623483 Mon Sep 17 00:00:00 2001 From: Gennadiy Litvinyuk Date: Fri, 5 Feb 2016 15:03:19 +0100 Subject: [PATCH 13/29] Preserve License info in Closure Compiler To preserve license info in Closure Compiler the license has to be JSDoc-comment (not simple comment) and have @license before license text --- Gruntfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index 97cfff06..ce85e9a4 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -22,7 +22,7 @@ module.exports = function(grunt) { dist: { options: { processContent: function(content) { - return grunt.template.process('/*!\n\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n@license\n*/\n') + return grunt.template.process('/**!\n\n @license\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n*/\n') + content; } }, From 1b885d496a9c9f2c9f9bc4c03eff79b6a70af45f Mon Sep 17 00:00:00 2001 From: "Mr. Leo" Date: Sat, 27 Feb 2016 12:11:25 +0100 Subject: [PATCH 14/29] Added cory --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 904b9e0c..8a16a352 100644 --- a/README.markdown +++ b/README.markdown @@ -121,6 +121,7 @@ Handlebars in the Wild * [Assemble](http://assemble.io), by [@jonschlinkert](https://github.com/jonschlinkert) and [@doowb](https://github.com/doowb), is a static site generator that uses Handlebars.js as its template engine. +* [Cory](https://github.com/leo/cory), by [@leo](https://github.com/leo), is another tiny static site generator * [CoSchedule](http://coschedule.com) An editorial calendar for WordPress that uses Handlebars.js * [dashbars](https://github.com/pismute/dashbars) A modern helper library for Handlebars.js. * [Ember.js](http://www.emberjs.com) makes Handlebars.js the primary way to From 8ff49cef529784d7815afdd6b2ef2398b1252d58 Mon Sep 17 00:00:00 2001 From: Charles O'Farrell Date: Sat, 20 Feb 2016 07:20:27 +1100 Subject: [PATCH 15/29] Ensure that existing blockParams and depths are respected on dupe programs Fixes #1186 --- lib/handlebars/compiler/javascript-compiler.js | 18 ++++++++++-------- spec/regressions.js | 9 +++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index 97939df0..ec891176 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -778,11 +778,11 @@ JavaScriptCompiler.prototype = { child = children[i]; compiler = new this.compiler(); // eslint-disable-line new-cap - let index = this.matchExistingProgram(child); + let existing = this.matchExistingProgram(child); - if (index == null) { + if (existing == null) { this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children - index = this.context.programs.length; + let index = this.context.programs.length; child.index = index; child.name = 'program' + index; this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile); @@ -791,12 +791,14 @@ JavaScriptCompiler.prototype = { this.useDepths = this.useDepths || compiler.useDepths; this.useBlockParams = this.useBlockParams || compiler.useBlockParams; + child.useDepths = this.useDepths; + child.useBlockParams = this.useBlockParams; } else { - child.index = index; - child.name = 'program' + index; + child.index = existing.index; + child.name = 'program' + existing.index; - this.useDepths = this.useDepths || child.useDepths; - this.useBlockParams = this.useBlockParams || child.useBlockParams; + this.useDepths = this.useDepths || existing.useDepths; + this.useBlockParams = this.useBlockParams || existing.useBlockParams; } } }, @@ -804,7 +806,7 @@ JavaScriptCompiler.prototype = { 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; + return environment; } } }, diff --git a/spec/regressions.js b/spec/regressions.js index a1eec2f1..4a2a55cd 100644 --- a/spec/regressions.js +++ b/spec/regressions.js @@ -268,4 +268,13 @@ describe('Regressions', function() { ' 1. IF: John--\n' + ' 2. MYIF: John==\n'); }); + + it('GH-1186: Support block params for existing programs', function() { + var string = + '{{#*inline "test"}}{{> @partial-block }}{{/inline}}' + + '{{#>test }}{{#each listOne as |item|}}{{ item }}{{/each}}{{/test}}' + + '{{#>test }}{{#each listTwo as |item|}}{{ item }}{{/each}}{{/test}}'; + + shouldCompileTo(string, { listOne: ['a'], listTwo: ['b']}, 'ab', ''); + }); }); From 0d0c4d1bbdef78bb4905a4f62b963134f729af8c Mon Sep 17 00:00:00 2001 From: Kabir Date: Tue, 12 Apr 2016 16:17:12 +0545 Subject: [PATCH 16/29] Add a new lightweight package based on handlebars in the README Add a new package [just-handlebars-helpers](https://github.com/leapfrogtechnology/just-handlebars-helpers) on the list. This is a lightweight package that offers a collection of common handlebars helpers. And it is [fully tested](https://codecov.io/github/leapfrogtechnology/just-handlebars-helpers) --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 8a16a352..89e3fc59 100644 --- a/README.markdown +++ b/README.markdown @@ -151,6 +151,7 @@ Handlebars in the Wild * [Swag](https://github.com/elving/swag) by [@elving](https://github.com/elving) is a growing collection of helpers for handlebars.js. Give your handlebars.js templates some swag son! * [DOMBars](https://github.com/blakeembrey/dombars) is a DOM-based templating engine built on the Handlebars parser and runtime **DEPRECATED** * [promised-handlebars](https://github.com/nknapp/promised-handlebars) is a wrapper for Handlebars that allows helpers to return Promises. +* [just-handlebars-helpers](https://github.com/leapfrogtechnology/just-handlebars-helpers) A fully tested lightweight package with common Handlebars helpers. External Resources ------------------ From ef9e0dc2ab5325172f8f74361c29818ae5f54d5f Mon Sep 17 00:00:00 2001 From: Lon Ingram Date: Tue, 16 Aug 2016 15:47:33 -0500 Subject: [PATCH 17/29] Walk up data frames for nested @partial-block The root cause of #1218 is that `invokePartial` creates a stack of data frames for nested partial blocks, but `resolvePartial` always uses the value at top of the stack without "popping" it. The result is an infinite recursive loop, as references to `@partial-block` in the partial at the top of the stack resolve to itself. So, walk up the stack of data frames when evaluating. This is accomplished by 1) setting the `partial-block` property to `noop` after use and 2) using `_parent['partial-block']` if `partial-block` is `noop` Fix #1218 --- lib/handlebars/runtime.js | 7 ++++++- spec/partials.js | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index 70493ce2..103b5afa 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -210,7 +210,12 @@ export function wrapProgram(container, i, fn, data, declaredBlockParams, blockPa export function resolvePartial(partial, context, options) { if (!partial) { if (options.name === '@partial-block') { - partial = options.data['partial-block']; + let data = options.data; + while (data['partial-block'] === noop) { + data = data._parent; + } + partial = data['partial-block']; + data['partial-block'] = noop; } else { partial = options.partials[options.name]; } diff --git a/spec/partials.js b/spec/partials.js index d3ead745..07d1c0d6 100644 --- a/spec/partials.js +++ b/spec/partials.js @@ -270,6 +270,20 @@ describe('partials', function() { true, 'success'); }); + it('should render nested partial blocks', function() { + shouldCompileToWithPartials( + '.template-start.{{#> outer}}{{value}}{{/outer}}.template-end.', + [ + {value: 'success'}, + {}, + { + outer: '.outer-start.{{#> nested}}.outer-partial-block-start.{{> @partial-block}}.outer-partial-block-end.{{/nested}}.outer-end.', + nested: '.nested-start.{{> @partial-block}}.nested-end.' + } + ], + true, + '.template-start..outer-start..nested-start..outer-partial-block-start.success.outer-partial-block-end..nested-end..outer-end..template-end.'); + }); }); describe('inline partials', function() { From 5ee91cb58a068563c72e4d10e8f0a185f3e43450 Mon Sep 17 00:00:00 2001 From: Lon Ingram Date: Wed, 17 Aug 2016 13:32:50 -0500 Subject: [PATCH 18/29] Add test reproducing #1185 --- spec/partials.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/partials.js b/spec/partials.js index 07d1c0d6..fcfc7803 100644 --- a/spec/partials.js +++ b/spec/partials.js @@ -323,6 +323,15 @@ describe('partials', function() { true, 'success'); }); + it('should render nested inline partials', function() { + shouldCompileToWithPartials( + '{{#*inline "outer"}}{{#>inner}}{{>@partial-block}}{{/inner}}{{/inline}}' + + '{{#*inline "inner"}}{{>@partial-block}}{{/inline}}' + + '{{#>outer}}{{value}}{{/outer}}', + [{value: 'success'}, {}, {}], + true, + 'success'); + }); }); it('should pass compiler flags', function() { From abc160ae8eb663efb30ea76aa656062f63e0f04d Mon Sep 17 00:00:00 2001 From: Lon Ingram Date: Wed, 17 Aug 2016 13:36:16 -0500 Subject: [PATCH 19/29] Use XML-like tags in test instead of bizarre dot delimiters --- spec/partials.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/partials.js b/spec/partials.js index fcfc7803..d6baba50 100644 --- a/spec/partials.js +++ b/spec/partials.js @@ -272,17 +272,17 @@ describe('partials', function() { }); it('should render nested partial blocks', function() { shouldCompileToWithPartials( - '.template-start.{{#> outer}}{{value}}{{/outer}}.template-end.', + '', [ {value: 'success'}, {}, { - outer: '.outer-start.{{#> nested}}.outer-partial-block-start.{{> @partial-block}}.outer-partial-block-end.{{/nested}}.outer-end.', - nested: '.nested-start.{{> @partial-block}}.nested-end.' + outer: '{{#> nested}}{{> @partial-block}}{{/nested}}', + nested: '{{> @partial-block}}' } ], true, - '.template-start..outer-start..nested-start..outer-partial-block-start.success.outer-partial-block-end..nested-end..outer-end..template-end.'); + ''); }); }); From 3385de0921e4512c4ca0a4faa6aa6f44dd969cd1 Mon Sep 17 00:00:00 2001 From: Lon Ingram Date: Fri, 11 Nov 2016 12:04:25 -0600 Subject: [PATCH 20/29] v4.0.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a5b78879..4ee3aede 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "handlebars", "barename": "handlebars", - "version": "4.0.5", + "version": "4.0.6", "description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration", "homepage": "http://www.handlebarsjs.com/", "keywords": [ From 44ce5f40aa5b6a4a9b41d92c9e4e1480b7937ae4 Mon Sep 17 00:00:00 2001 From: Lon Ingram Date: Sat, 12 Nov 2016 10:38:46 -0600 Subject: [PATCH 21/29] Update release notes --- release-notes.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/release-notes.md b/release-notes.md index 497f5e89..8b073d52 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,7 +2,28 @@ ## Development -[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.5...master) +[Commits](https://github.com/lawnsea/handlebars.js/compare/v4.0.6...master) + +## v4.0.6 - November 12th, 2016 +- [#1243](https://github.com/wycats/handlebars.js/pull/1243) - Walk up data frames for nested @partial-block ([@lawnsea](https://github.com/lawnsea)) +- [#1210](https://github.com/wycats/handlebars.js/pull/1210) - Add a new lightweight package based on handlebars in the README ([@kabirbaidhya](https://github.com/kabirbaidhya)) +- [#1187](https://github.com/wycats/handlebars.js/pull/1187) - Ensure that existing blockParams and depths are respected on dupe programs ([@charleso](https://github.com/charleso)) +- [#1191](https://github.com/wycats/handlebars.js/pull/1191) - Added cory ([@leo](https://github.com/leo)) +- [#1177](https://github.com/wycats/handlebars.js/pull/1177) - Preserve License info in Closure Compiler ([@gennadiylitvinyuk](https://github.com/gennadiylitvinyuk)) +- [#1171](https://github.com/wycats/handlebars.js/pull/1171) - Contributing doc fix: failing thats -> failing tests ([@paulfalgout](https://github.com/paulfalgout)) +- [#1166](https://github.com/wycats/handlebars.js/pull/1166) - Update license date ([@timwangdev](https://github.com/timwangdev)) +- Update jsfiddle to point to latest - 959ee55 (originally dfc7554 by [@kpdecker](https://github.com/kpdecker)) +- [#1163](https://github.com/wycats/handlebars.js/pull/1163) - Fix typos on decorators-api.md. ([@adjohnson916](https://github.com/adjohnson916)) +- Drop extra Error params - 8c19874 (originally 63fdb92 by [@kpdecker](https://github.com/kpdecker)) +- [#1153](https://github.com/wycats/handlebars.js/pull/1153) - Add documentation for running tests to contributing.md ([@ryanmurakami](https://github.com/ryanmurakami)) +- Avoid error in older browsers in test - 400916c (originally a6121ca by [@kpdecker](https://github.com/kpdecker)) +- Update target browser test versions - fee2334 (originally 871c32a by [@kpdecker](https://github.com/kpdecker)) +- Exclude coverage check in exception conditional - 32d6363 (originally 326734b by [@kpdecker](https://github.com/kpdecker)) +- Fix throw when creating exception object in Safari - 20c965c (originally 2ea6119 by [@kpdecker](https://github.com/kpdecker)) +- Update build for modern node versions - 6c9f98c (originally 8289c0b by [@kpdecker](https://github.com/kpdecker)) +- [#1135](https://github.com/wycats/handlebars.js/issues/1135) - Relax depth check for context push - c393c81 (originally 25458fd by [@kpdecker](https://github.com/kpdecker)) + +[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.5...v4.0.6) ## v4.0.5 - November 19th, 2015 - [#1132](https://github.com/wycats/handlebars.js/pull/1132) - Update uglify-js to avoid vulnerability ([@plynchnlm](https://api.github.com/users/plynchnlm)) From ad3037cf54132fc5f589134d3bef961a5f751973 Mon Sep 17 00:00:00 2001 From: Lon Ingram Date: Sat, 12 Nov 2016 12:32:45 -0600 Subject: [PATCH 22/29] v4.0.6 (again) Missed some versions in the repo that needed bumping. --- components/bower.json | 2 +- components/handlebars.js.nuspec | 2 +- lib/handlebars/base.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bower.json b/components/bower.json index 840c7723..c67efbb5 100644 --- a/components/bower.json +++ b/components/bower.json @@ -1,6 +1,6 @@ { "name": "handlebars", - "version": "4.0.5", + "version": "4.0.6", "main": "handlebars.js", "license": "MIT", "dependencies": {} diff --git a/components/handlebars.js.nuspec b/components/handlebars.js.nuspec index 9ede3d60..1145f057 100644 --- a/components/handlebars.js.nuspec +++ b/components/handlebars.js.nuspec @@ -2,7 +2,7 @@ handlebars.js - 4.0.5 + 4.0.6 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 836422d1..155e7ca0 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.5'; +export const VERSION = '4.0.6'; export const COMPILER_REVISION = 7; export const REVISION_CHANGES = { From c7dc3539566dac1fbc82661b432ee26c4731548a Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Tue, 20 Dec 2016 09:32:18 +0100 Subject: [PATCH 23/29] Testcase to verify that compile-errors have a column-property Related to #1284 The test ensures that the property is there, because it is important to some people. --- spec/compiler.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/compiler.js b/spec/compiler.js index be1fb007..9eaba4a2 100644 --- a/spec/compiler.js +++ b/spec/compiler.js @@ -38,6 +38,22 @@ describe('compiler', function() { }, Error, 'You must pass a string or Handlebars AST to Handlebars.compile. You passed [object Object]'); }); + it('should include the location in the error (row and column)', function() { + try { + Handlebars.compile(' \n {{#if}}\n{{/def}}')(); + equal(true, false, 'Statement must throw exception. This line should not be executed.'); + } catch (err) { + equal(err.message, 'if doesn\'t match def - 2:5', 'Checking error message'); + if (Object.getOwnPropertyDescriptor(err, 'column').writable) { + // In Safari 8, the column-property is read-only. This means that even if it is set with defineProperty, + // its value won't change (https://github.com/jquery/esprima/issues/1290#issuecomment-132455482) + // Since this was neither working in Handlebars 3 nor in 4.0.5, we only check the column for other browsers. + equal(err.column, 5, 'Checking error column'); + } + equal(err.lineNumber, 2, 'Checking error row'); + } + }); + it('can utilize AST instance', function() { equal(Handlebars.compile({ type: 'Program', From a023cb4dd98f09944d2cec8da481a1b3043e281f Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Wed, 21 Dec 2016 22:22:08 +0100 Subject: [PATCH 24/29] Make "column"-property of Errors enumerable Fixes #1284 Appearently, there is a use-case of stringifying the error in order to evaluated its properties on another system. There was a regression from 4.0.5 to 4.0.6 that the column-property of compilation errors was not enumerable anymore in 4.0.6 (due to commit 20c965c) and thus was not included in the output of "JSON.stringify". --- lib/handlebars/exception.js | 5 ++++- spec/compiler.js | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/handlebars/exception.js b/lib/handlebars/exception.js index 08ae531a..b9a5557b 100644 --- a/lib/handlebars/exception.js +++ b/lib/handlebars/exception.js @@ -31,7 +31,10 @@ function Exception(message, node) { // Work around issue under safari where we can't directly set the column value /* istanbul ignore next */ if (Object.defineProperty) { - Object.defineProperty(this, 'column', {value: column}); + Object.defineProperty(this, 'column', { + value: column, + enumerable: true + }); } else { this.column = column; } diff --git a/spec/compiler.js b/spec/compiler.js index 9eaba4a2..95941bcc 100644 --- a/spec/compiler.js +++ b/spec/compiler.js @@ -54,6 +54,15 @@ describe('compiler', function() { } }); + it('should include the location as enumerable property', function() { + try { + Handlebars.compile(' \n {{#if}}\n{{/def}}')(); + equal(true, false, 'Statement must throw exception. This line should not be executed.'); + } catch (err) { + equal(err.propertyIsEnumerable('column'), true, 'Checking error column'); + } + }); + it('can utilize AST instance', function() { equal(Handlebars.compile({ type: 'Program', From 406f2ee01f5cf8e5c9430f76c723dc6251c6959c Mon Sep 17 00:00:00 2001 From: Travis Nelson Date: Wed, 16 Nov 2016 04:32:53 +0100 Subject: [PATCH 25/29] require('sys') is deprecated, using 'util' instead (node:30288) DeprecationWarning: sys is deprecated. Use util instead. (cherry picked from commit 9a36966 by @travnels) --- bench/util/benchwarmer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/util/benchwarmer.js b/bench/util/benchwarmer.js index 78b1a347..49f66f73 100644 --- a/bench/util/benchwarmer.js +++ b/bench/util/benchwarmer.js @@ -11,7 +11,7 @@ function BenchWarmer() { this.errors = {}; } -var print = require('sys').print; +var print = require('util').print; BenchWarmer.prototype = { winners: function(benches) { From 01b0f656bb32916c714aa7c1438a788dde6c6210 Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Mon, 13 Feb 2017 23:10:13 +0100 Subject: [PATCH 26/29] Avoid duplicate "sourceMappingURL=" lines. Avoid duplicate // sourceMappingURL=... lines when minifying AND generating a map. UglifyJS2 will write the line when minifying. (cherry picked from commit 660a117) --- lib/precompiler.js | 3 --- spec/precompiler.js | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/precompiler.js b/lib/precompiler.js index a20d1419..6ba3800c 100644 --- a/lib/precompiler.js +++ b/lib/precompiler.js @@ -250,9 +250,6 @@ module.exports.cli = function(opts) { outSourceMap: opts.map, inSourceMap: JSON.parse(output.map) }); - if (opts.map) { - output.code += '\n//# sourceMappingURL=' + opts.map + '\n'; - } } if (opts.map) { diff --git a/spec/precompiler.js b/spec/precompiler.js index f9759a9c..006a37e3 100644 --- a/spec/precompiler.js +++ b/spec/precompiler.js @@ -152,14 +152,14 @@ describe('precompiler', function() { Precompiler.cli({templates: [emptyTemplate], map: 'foo.js.map'}); equal(file, 'foo.js.map'); - equal(/sourceMappingURL=/.test(log), true); + equal(log.match(/sourceMappingURL=/g).length, 1); }); it('should output map', function() { Precompiler.cli({templates: [emptyTemplate], min: true, map: 'foo.js.map'}); equal(file, 'foo.js.map'); - equal(/sourceMappingURL=/.test(log), true); + equal(log.match(/sourceMappingURL=/g).length, 1); }); describe('#loadTemplates', function() { From 5a164d0ca5a4dbda07b38fd55199bb65dfeda55e Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Sat, 31 Dec 2016 00:32:03 +0100 Subject: [PATCH 27/29] Fix for #1252: Using @partial-block twice in a template not possible Fixes #1252 - This fix treats partial-blocks more like closures and uses the closure-context of the "invokePartial"-function to store the @partial-block for the partial. - Adds a tes for the fix --- lib/handlebars/runtime.js | 24 ++++++++++++++---------- spec/partials.js | 7 +++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index 103b5afa..5a79b710 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -210,12 +210,7 @@ export function wrapProgram(container, i, fn, data, declaredBlockParams, blockPa export function resolvePartial(partial, context, options) { if (!partial) { if (options.name === '@partial-block') { - let data = options.data; - while (data['partial-block'] === noop) { - data = data._parent; - } - partial = data['partial-block']; - data['partial-block'] = noop; + partial = options.data['partial-block']; } else { partial = options.partials[options.name]; } @@ -228,6 +223,8 @@ export function resolvePartial(partial, context, options) { } export function invokePartial(partial, context, options) { + // Use the current closure context to save the partial-block if this partial + const currentPartialBlock = options.data && options.data['partial-block']; options.partial = true; if (options.ids) { options.data.contextPath = options.ids[0] || options.data.contextPath; @@ -236,10 +233,17 @@ 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) { - options.partials = Utils.extend({}, options.partials, partialBlock.partials); + // Wrapper function to get access to currentPartialBlock from the closure + let fn = options.fn; + partialBlock = options.data['partial-block'] = function partialBlockWrapper(context, options) { + // Restore the partial-block from the closure for the execution of the block + // i.e. the part inside the block of the partial call. + options.data = createFrame(options.data); + options.data['partial-block'] = currentPartialBlock; + return fn(context, options); + }; + if (fn.partials) { + options.partials = Utils.extend({}, options.partials, fn.partials); } } diff --git a/spec/partials.js b/spec/partials.js index d6baba50..cbec5886 100644 --- a/spec/partials.js +++ b/spec/partials.js @@ -249,6 +249,13 @@ describe('partials', function() { true, 'success'); }); + it('should be able to render the partial-block twice', function() { + shouldCompileToWithPartials( + '{{#> dude}}success{{/dude}}', + [{}, {}, {dude: '{{> @partial-block }} {{> @partial-block }}'}], + true, + 'success success'); + }); it('should render block from partial with context', function() { shouldCompileToWithPartials( '{{#> dude}}{{value}}{{/dude}}', From 63a8e0caa29cae4720fd90a4b3a9b1c50832afe8 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Mon, 2 Jan 2017 10:05:21 +0100 Subject: [PATCH 28/29] Add more tests for partial-blocks and inline partials - Multiple partial-blocks at different nesting levels - Calling partial-blocks twice with nested partial-blocks - Calling the partial-block from within the #each-helper - nested inline partials with partial-blocks on different nesting levels - nested inline partials (twice at each level) --- spec/partials.js | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/spec/partials.js b/spec/partials.js index cbec5886..266837db 100644 --- a/spec/partials.js +++ b/spec/partials.js @@ -263,6 +263,32 @@ describe('partials', function() { true, 'success'); }); + it('should allow the #each-helper to be used along with partial-blocks', function() { + shouldCompileToWithPartials( + '', + [ + {value: ['a', 'b', 'c']}, + {}, + { + list: '{{#each .}}{{> @partial-block}}{{/each}}' + } + ], + true, + ''); + }); + it('should render block from partial with context (twice)', function() { + shouldCompileToWithPartials( + '{{#> dude}}{{value}}{{/dude}}', + [ + {context: {value: 'success'}}, + {}, + { + dude: '{{#with context}}{{> @partial-block }} {{> @partial-block }}{{/with}}' + } + ], + true, + 'success success'); + }); it('should render block from partial with context', function() { shouldCompileToWithPartials( '{{#> dude}}{{../context/value}}{{/dude}}', @@ -291,6 +317,50 @@ describe('partials', function() { true, ''); }); + it('should render nested partial blocks at different nesting levels', function() { + shouldCompileToWithPartials( + '', + [ + {value: 'success'}, + {}, + { + outer: '{{#> nested}}{{> @partial-block}}{{/nested}}{{> @partial-block}}', + nested: '{{> @partial-block}}' + } + ], + true, + ''); + }); + it('should render nested partial blocks at different nesting levels (twice)', function() { + shouldCompileToWithPartials( + '', + [ + {value: 'success'}, + {}, + { + outer: '{{#> nested}}{{> @partial-block}} {{> @partial-block}}{{/nested}}{{> @partial-block}}+{{> @partial-block}}', + nested: '{{> @partial-block}}' + } + ], + true, + ''); + }); + it('should render nested partial blocks (twice at each level)', function() { + shouldCompileToWithPartials( + '', + [ + {value: 'success'}, + {}, + { + outer: '{{#> nested}}{{> @partial-block}} {{> @partial-block}}{{/nested}}', + nested: '{{> @partial-block}}{{> @partial-block}}' + } + ], + true, + ''); + }); }); describe('inline partials', function() { @@ -339,6 +409,24 @@ describe('partials', function() { true, 'success'); }); + it('should render nested inline partials with partial-blocks on different nesting levels', function() { + shouldCompileToWithPartials( + '{{#*inline "outer"}}{{#>inner}}{{>@partial-block}}{{/inner}}{{>@partial-block}}{{/inline}}' + + '{{#*inline "inner"}}{{>@partial-block}}{{/inline}}' + + '{{#>outer}}{{value}}{{/outer}}', + [{value: 'success'}, {}, {}], + true, + 'successsuccess'); + }); + it('should render nested inline partials (twice at each level)', function() { + shouldCompileToWithPartials( + '{{#*inline "outer"}}{{#>inner}}{{>@partial-block}} {{>@partial-block}}{{/inner}}{{/inline}}' + + '{{#*inline "inner"}}{{>@partial-block}}{{>@partial-block}}{{/inline}}' + + '{{#>outer}}{{value}}{{/outer}}', + [{value: 'success'}, {}, {}], + true, + 'success successsuccess success'); + }); }); it('should pass compiler flags', function() { From 911e676af477f24b376462db80e0063c8d07d3d6 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Tue, 14 Feb 2017 23:10:02 +0100 Subject: [PATCH 29/29] Merge branch '4.x' # Conflicts: # Gruntfile.js # lib/handlebars/exception.js # spec/partials.js # spec/regressions.js --- lib/handlebars/runtime.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index eb5789fc..310b108e 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -197,12 +197,7 @@ export function wrapProgram(container, i, fn, data, declaredBlockParams, blockPa export function resolvePartial(partial, context, options) { if (!partial) { if (options.name === '@partial-block') { - let data = options.data; - while (data['partial-block'] === noop) { - data = data._parent; - } - partial = data['partial-block']; - data['partial-block'] = noop; + partial = options.data['partial-block']; } else { partial = options.partials[options.name]; }