diff --git a/components/bower.json b/components/bower.json index 9f8f5ec0f..5d706f568 100644 --- a/components/bower.json +++ b/components/bower.json @@ -1,6 +1,6 @@ { "name": "handlebars", - "version": "4.3.4", + "version": "4.4.0", "main": "handlebars.js", "license": "MIT", "dependencies": {} diff --git a/components/handlebars.js.nuspec b/components/handlebars.js.nuspec index eb693b3cf..349fe4e89 100644 --- a/components/handlebars.js.nuspec +++ b/components/handlebars.js.nuspec @@ -2,7 +2,7 @@ handlebars.js - 4.3.4 + 4.4.0 handlebars.js Authors https://github.com/wycats/handlebars.js/blob/master/LICENSE https://github.com/wycats/handlebars.js/ diff --git a/components/package.json b/components/package.json index 11d5e3b70..326734da9 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "handlebars", - "version": "4.3.4", + "version": "4.4.0", "license": "MIT", "jspm": { "main": "handlebars", diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index 312090345..cf0df5220 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.3.4'; +export const VERSION = '4.4.0'; export const COMPILER_REVISION = 8; export const LAST_COMPATIBLE_COMPILER_REVISION = 7; diff --git a/lib/handlebars/helpers/each.js b/lib/handlebars/helpers/each.js index fb11903c8..ce549b5c7 100644 --- a/lib/handlebars/helpers/each.js +++ b/lib/handlebars/helpers/each.js @@ -49,6 +49,16 @@ export default function(instance) { execIteration(i, i, i === context.length - 1); } } + } else if (global.Symbol && context[global.Symbol.iterator]) { + const newContext = []; + const iterator = context[global.Symbol.iterator](); + for (let it = iterator.next(); !it.done; it = iterator.next()) { + newContext.push(it.value); + } + context = newContext; + for (let j = context.length; i < j; i++) { + execIteration(i, i, i === context.length - 1); + } } else { let priorKey; diff --git a/package.json b/package.json index 788600ce8..78e414b21 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "handlebars", "barename": "handlebars", - "version": "4.3.4", + "version": "4.4.0", "description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration", "homepage": "http://www.handlebarsjs.com/", "keywords": [ diff --git a/release-notes.md b/release-notes.md index dec4f9861..c8d7c6d50 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,7 +2,13 @@ ## Development -[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.4...master) +[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.0...master) + +## v4.4.0 - September 29th, 2019 +- Added support for iterable objects in {{#each}} helper (#1557) - cf7545e + + +[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.4...v4.4.0) ## v4.3.4 - September 28th, 2019 - fix: harden "propertyIsEnumerable"-check - ff4d827 diff --git a/spec/builtins.js b/spec/builtins.js index ce6d8f4e8..b29927f06 100644 --- a/spec/builtins.js +++ b/spec/builtins.js @@ -254,6 +254,37 @@ describe('builtin helpers', function() { template({}); }, handlebarsEnv.Exception, 'Must pass iterator to #each'); }); + + if (global.Symbol && global.Symbol.iterator) { + it('each on iterable', function() { + function Iterator(arr) { + this.arr = arr; + this.index = 0; + } + Iterator.prototype.next = function() { + var value = this.arr[this.index]; + var done = this.index === this.arr.length; + if (!done) { + this.index++; + } + return { value: value, done: done }; + }; + function Iterable(arr) { + this.arr = arr; + } + Iterable.prototype[global.Symbol.iterator] = function() { + return new Iterator(this.arr); + }; + var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; + var goodbyes = new Iterable([{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]); + var goodbyesEmpty = new Iterable([]); + var hash = {goodbyes: goodbyes, world: 'world'}; + shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!', + 'each with array argument iterates over the contents when not empty'); + shouldCompileTo(string, {goodbyes: goodbyesEmpty, world: 'world'}, 'cruel world!', + 'each with array argument ignores the contents when empty'); + }); + } }); describe('#log', function() {