From 0872fb669906bfa1526daeb48f81562a254a930a Mon Sep 17 00:00:00 2001 From: John Freeman Date: Sat, 31 Mar 2012 23:09:27 -0500 Subject: [PATCH 01/42] block helper "with" should check for empty context --- lib/handlebars/base.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index 36ec257c4..f7e04a6f8 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -88,7 +88,7 @@ Handlebars.registerHelper('unless', function(context, options) { }); Handlebars.registerHelper('with', function(context, options) { - return options.fn(context); + if (!Handlebars.Utils.isEmpty(context)) return options.fn(context); }); Handlebars.registerHelper('log', function(context) { From 53d6b4ca047bed2f206bbbe0cce57b6b7e5c6088 Mon Sep 17 00:00:00 2001 From: Matteo Agosti Date: Tue, 23 Oct 2012 16:05:27 +0200 Subject: [PATCH 02/42] Supporting custom template extension Fix missing escape --- bin/handlebars | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/bin/handlebars b/bin/handlebars index 7a2fc1cac..f83901ddb 100755 --- a/bin/handlebars +++ b/bin/handlebars @@ -42,6 +42,12 @@ var optimist = require('optimist') 'type': 'string', 'description': 'Template root. Base value that will be stripped from template names.', 'alias': 'root' + }, + 'e': { + 'type': 'string', + 'description': 'Template extension.', + 'alias': 'extension', + 'default': 'handlebars' } }) @@ -87,6 +93,9 @@ if (argv.known) { } } +// Build file extension pattern +var extension = new RegExp('\\.' + argv.extension + '$'); + var output = []; if (!argv.simple) { if (argv.amd) { @@ -103,7 +112,7 @@ function processTemplate(template, root) { fs.readdirSync(template).map(function(file) { var path = template + '/' + file; - if (/\.handlebars$/.test(path) || fs.statSync(path).isDirectory()) { + if (extension.test(path) || fs.statSync(path).isDirectory()) { processTemplate(path, root || template); } }); @@ -121,7 +130,7 @@ function processTemplate(template, root) { } else if (template.indexOf(root) === 0) { template = template.substring(root.length+1); } - template = template.replace(/\.handlebars$/, ''); + template = template.replace(extension, ''); if (argv.simple) { output.push(handlebars.precompile(data, options) + '\n'); From baccdb4cfc241cbcfd02d21aada56100c6c9c132 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 17 Feb 2013 04:27:42 -0600 Subject: [PATCH 03/42] Add program metadata Include program id and depth on the generated wrapper objects. This allows helpers who are passed these objects to differentiate between helpers for cases where they may want to cache the generated DOM structure. --- lib/handlebars/base.js | 5 +++-- lib/handlebars/compiler/compiler.js | 7 +------ lib/handlebars/runtime.js | 26 +++++++++++++++----------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index dcbd95889..a455a89d6 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -7,11 +7,12 @@ var Handlebars = {}; // BEGIN(BROWSER) Handlebars.VERSION = "1.0.0-rc.3"; -Handlebars.COMPILER_REVISION = 2; +Handlebars.COMPILER_REVISION = 3; Handlebars.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' + 2: '== 1.0.0-rc.3', + 3: '>= 1.0.0-rc.4' }; Handlebars.helpers = {}; diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index 196ba18bb..32a072090 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -993,12 +993,7 @@ JavaScriptCompiler.prototype = { else { programParams.push("depth" + (depth - 1)); } } - if(depths.length === 0) { - return "self.program(" + programParams.join(", ") + ")"; - } else { - programParams.shift(); - return "self.programWithDepth(" + programParams.join(", ") + ")"; - } + return (depths.length === 0 ? "self.program(" : "self.programWithDepth(") + programParams.join(", ") + ")"; }, register: function(name, val) { diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index 805e10fbd..d99019d9e 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -12,13 +12,11 @@ Handlebars.VM = { program: function(i, fn, data) { var programWrapper = this.programs[i]; if(data) { - return Handlebars.VM.program(fn, data); - } else if(programWrapper) { - return programWrapper; - } else { - programWrapper = this.programs[i] = Handlebars.VM.program(fn); - return programWrapper; + programWrapper = Handlebars.VM.program(i, fn, data); + } else if (!programWrapper) { + programWrapper = this.programs[i] = Handlebars.VM.program(i, fn); } + return programWrapper; }, programWithDepth: Handlebars.VM.programWithDepth, noop: Handlebars.VM.noop, @@ -50,21 +48,27 @@ Handlebars.VM = { }; }, - programWithDepth: function(fn, data, $depth) { - var args = Array.prototype.slice.call(arguments, 2); + programWithDepth: function(i, fn, data /*, $depth */) { + var args = Array.prototype.slice.call(arguments, 3); - return function(context, options) { + var program = function(context, options) { options = options || {}; return fn.apply(this, [context, options.data || data].concat(args)); }; + program.program = i; + program.depth = args.length; + return program; }, - program: function(fn, data) { - return function(context, options) { + program: function(i, fn, data) { + var program = function(context, options) { options = options || {}; return fn(context, options.data || data); }; + program.program = i; + program.depth = 0; + return program; }, noop: function() { return ""; }, invokePartial: function(partial, name, context, helpers, partials, data) { From bf30bf911562a11764c768f76e2490b51423ff91 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Fiset Date: Mon, 4 Mar 2013 13:25:00 -0500 Subject: [PATCH 04/42] Allow accessing properties in current context using paths. This is to avoid name collisions with registered helper functions. Issue #458 --- src/handlebars.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handlebars.l b/src/handlebars.l index b32e39c64..970aaddf4 100644 --- a/src/handlebars.l +++ b/src/handlebars.l @@ -31,7 +31,7 @@ "{{" { return 'OPEN'; } "=" { return 'EQUALS'; } -"."/[} ] { return 'ID'; } +"."/[}/ ] { return 'ID'; } ".." { return 'ID'; } [\/.] { return 'SEP'; } \s+ { /*ignore whitespace*/ } From 681f1a63961b04c68dc4e671513675e946f6f3f9 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Fiset Date: Mon, 4 Mar 2013 13:33:13 -0500 Subject: [PATCH 05/42] Allow colon characters in identifiers Issue #460 --- src/handlebars.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handlebars.l b/src/handlebars.l index 970aaddf4..d2f996348 100644 --- a/src/handlebars.l +++ b/src/handlebars.l @@ -43,7 +43,7 @@ "true"/[}\s] { return 'BOOLEAN'; } "false"/[}\s] { return 'BOOLEAN'; } \-?[0-9]+/[}\s] { return 'INTEGER'; } -[a-zA-Z0-9_$-]+/[=}\s\/.] { return 'ID'; } +[a-zA-Z0-9_$:-]+/[=}\s\/.] { return 'ID'; } '['[^\]]*']' { yytext = yytext.substr(1, yyleng-2); return 'ID'; } . { return 'INVALID'; } \s+ { /*ignore whitespace*/ } From e4a0ac4b040d9ab0decf547c6e4684f86befc99b Mon Sep 17 00:00:00 2001 From: Chris Broadfoot Date: Mon, 4 Mar 2013 16:08:00 -0800 Subject: [PATCH 06/42] Fix Rhino support --- src/handlebars.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handlebars.l b/src/handlebars.l index b32e39c64..5fa2bc0d8 100644 --- a/src/handlebars.l +++ b/src/handlebars.l @@ -47,7 +47,7 @@ '['[^\]]*']' { yytext = yytext.substr(1, yyleng-2); return 'ID'; } . { return 'INVALID'; } \s+ { /*ignore whitespace*/ } -[a-zA-Z0-9_$-/]+ { this.popState(); return 'PARTIAL_NAME'; } +[a-zA-Z0-9_$-\/]+ { this.popState(); return 'PARTIAL_NAME'; } <> { return 'EOF'; } From bcc15ea5e78a3368344204c805e4666681e7253e Mon Sep 17 00:00:00 2001 From: kpdecker Date: Wed, 13 Mar 2013 21:56:30 -0500 Subject: [PATCH 07/42] Rebuild dist --- dist/handlebars.js | 2 +- dist/handlebars.runtime.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/handlebars.js b/dist/handlebars.js index 39afa6419..87214df29 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -156,7 +156,7 @@ Handlebars.registerHelper('unless', function(context, options) { }); Handlebars.registerHelper('with', function(context, options) { - return options.fn(context); + if (!Handlebars.Utils.isEmpty(context)) return options.fn(context); }); Handlebars.registerHelper('log', function(context, options) { diff --git a/dist/handlebars.runtime.js b/dist/handlebars.runtime.js index a55b30fd4..4779ad0a3 100644 --- a/dist/handlebars.runtime.js +++ b/dist/handlebars.runtime.js @@ -156,7 +156,7 @@ Handlebars.registerHelper('unless', function(context, options) { }); Handlebars.registerHelper('with', function(context, options) { - return options.fn(context); + if (!Handlebars.Utils.isEmpty(context)) return options.fn(context); }); Handlebars.registerHelper('log', function(context, options) { From 53de75927ce3ff622901ae00b39c5e677fb6ba25 Mon Sep 17 00:00:00 2001 From: Les Hill Date: Mon, 25 Feb 2013 23:03:16 -0800 Subject: [PATCH 08/42] Add contexts for string mode hash values Allows for evaluating hash parameters such as ../city in string mode. --- dist/handlebars.js | 15 +++++++++++++-- lib/handlebars/compiler/compiler.js | 15 +++++++++++++-- spec/qunit_spec.js | 26 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/dist/handlebars.js b/dist/handlebars.js index 87214df29..2ae45a559 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -1023,6 +1023,10 @@ Compiler.prototype = { val = pair[1]; if (this.options.stringParams) { + if(val.depth) { + this.addDepth(val.depth); + } + this.opcode('getContext', val.depth || 0); this.opcode('pushStringParam', val.stringModeValue, val.type); } else { this.accept(val); @@ -1607,16 +1611,18 @@ JavaScriptCompiler.prototype = { if (this.options.stringParams) { this.register('hashTypes', '{}'); + this.register('hashContexts', '{}'); } }, pushHash: function() { - this.hash = {values: [], types: []}; + this.hash = {values: [], types: [], contexts: []}; }, popHash: function() { var hash = this.hash; this.hash = undefined; if (this.options.stringParams) { + this.register('hashContexts', '{' + hash.contexts.join(',') + '}'); this.register('hashTypes', '{' + hash.types.join(',') + '}'); } this.push('{\n ' + hash.values.join(',\n ') + '\n }'); @@ -1759,14 +1765,18 @@ JavaScriptCompiler.prototype = { // and pushes the hash back onto the stack. assignToHash: function(key) { var value = this.popStack(), + context, type; if (this.options.stringParams) { type = this.popStack(); - this.popStack(); + context = this.popStack(); } var hash = this.hash; + if (context) { + hash.contexts.push("'" + key + "': " + context); + } if (type) { hash.types.push("'" + key + "': " + type); } @@ -2020,6 +2030,7 @@ JavaScriptCompiler.prototype = { if (this.options.stringParams) { options.push("contexts:[" + contexts.join(",") + "]"); options.push("types:[" + types.join(",") + "]"); + options.push("hashContexts:hashContexts"); options.push("hashTypes:hashTypes"); } diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index 196ba18bb..cd902fd4f 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -189,6 +189,10 @@ Compiler.prototype = { val = pair[1]; if (this.options.stringParams) { + if(val.depth) { + this.addDepth(val.depth); + } + this.opcode('getContext', val.depth || 0); this.opcode('pushStringParam', val.stringModeValue, val.type); } else { this.accept(val); @@ -773,16 +777,18 @@ JavaScriptCompiler.prototype = { if (this.options.stringParams) { this.register('hashTypes', '{}'); + this.register('hashContexts', '{}'); } }, pushHash: function() { - this.hash = {values: [], types: []}; + this.hash = {values: [], types: [], contexts: []}; }, popHash: function() { var hash = this.hash; this.hash = undefined; if (this.options.stringParams) { + this.register('hashContexts', '{' + hash.contexts.join(',') + '}'); this.register('hashTypes', '{' + hash.types.join(',') + '}'); } this.push('{\n ' + hash.values.join(',\n ') + '\n }'); @@ -925,14 +931,18 @@ JavaScriptCompiler.prototype = { // and pushes the hash back onto the stack. assignToHash: function(key) { var value = this.popStack(), + context, type; if (this.options.stringParams) { type = this.popStack(); - this.popStack(); + context = this.popStack(); } var hash = this.hash; + if (context) { + hash.contexts.push("'" + key + "': " + context); + } if (type) { hash.types.push("'" + key + "': " + type); } @@ -1186,6 +1196,7 @@ JavaScriptCompiler.prototype = { if (this.options.stringParams) { options.push("contexts:[" + contexts.join(",") + "]"); options.push("types:[" + types.join(",") + "]"); + options.push("hashContexts:hashContexts"); options.push("hashTypes:hashTypes"); } diff --git a/spec/qunit_spec.js b/spec/qunit_spec.js index f12e44cd4..356c63cc7 100644 --- a/spec/qunit_spec.js +++ b/spec/qunit_spec.js @@ -1286,6 +1286,32 @@ test("in string mode, hash parameters get type information", function() { equal(result, "Helper called"); }); +test("in string mode, 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(options.types[0], "ID"); + + equal(options.contexts.length, 1); + equal(options.hashContexts.noun, context); + equal(options.hash.desire, "need"); + equal(options.hash.noun, "dad.joke"); + equal(options.hash.bool, true); + return "Helper called"; + }, + "with": function(context, options) { + return options.fn(options.contexts[0][context]); + } + }; + + var result = template(context, { helpers: helpers }); + equal(result, "Helper called"); +}); + test("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}); From 9e4b59e815b1f557c31fe5abc36b9be8aa0cf34a Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 31 Mar 2013 16:27:11 -0500 Subject: [PATCH 09/42] Add support for \\{ escapes Fixes #456 --- dist/handlebars.js | 64 ++++++++++++++++++++++++---------------------- spec/qunit_spec.js | 6 +++++ src/handlebars.l | 1 + 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/dist/handlebars.js b/dist/handlebars.js index 87214df29..5bd69b5c8 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -554,84 +554,86 @@ lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_STA var YYSTATE=YY_START switch($avoiding_name_collisions) { -case 0: +case 0: yy_.yytext = "\\"; return 14; +break; +case 1: if(yy_.yytext.slice(-1) !== "\\") this.begin("mu"); if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu"); if(yy_.yytext) return 14; break; -case 1: return 14; +case 2: return 14; break; -case 2: +case 3: if(yy_.yytext.slice(-1) !== "\\") this.popState(); if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1); return 14; break; -case 3: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15; -break; -case 4: this.begin("par"); return 24; +case 4: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15; break; -case 5: return 16; +case 5: this.begin("par"); return 24; break; -case 6: return 20; +case 6: return 16; break; -case 7: return 19; +case 7: return 20; break; case 8: return 19; break; -case 9: return 23; +case 9: return 19; break; case 10: return 23; break; -case 11: this.popState(); this.begin('com'); +case 11: return 23; break; -case 12: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15; +case 12: this.popState(); this.begin('com'); break; -case 13: return 22; +case 13: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15; break; -case 14: return 36; +case 14: return 22; break; -case 15: return 35; +case 15: return 36; break; case 16: return 35; break; -case 17: return 39; +case 17: return 35; break; -case 18: /*ignore whitespace*/ +case 18: return 39; break; -case 19: this.popState(); return 18; +case 19: /*ignore whitespace*/ break; case 20: this.popState(); return 18; break; -case 21: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 30; +case 21: this.popState(); return 18; break; -case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 30; +case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 30; break; -case 23: yy_.yytext = yy_.yytext.substr(1); return 28; +case 23: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 30; break; -case 24: return 32; +case 24: yy_.yytext = yy_.yytext.substr(1); return 28; break; case 25: return 32; break; -case 26: return 31; +case 26: return 32; +break; +case 27: return 31; break; -case 27: return 35; +case 28: return 35; break; -case 28: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 35; +case 29: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 35; break; -case 29: return 'INVALID'; +case 30: return 'INVALID'; break; -case 30: /*ignore whitespace*/ +case 31: /*ignore whitespace*/ break; -case 31: this.popState(); return 37; +case 32: this.popState(); return 37; break; -case 32: return 5; +case 33: return 5; break; } }; -lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-/]+)/,/^(?:$)/]; -lexer.conditions = {"mu":{"rules":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,32],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"par":{"rules":[30,31],"inclusive":false},"INITIAL":{"rules":[0,1,32],"inclusive":true}}; +lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-/]+)/,/^(?:$)/]; +lexer.conditions = {"mu":{"rules":[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,33],"inclusive":false},"emu":{"rules":[3],"inclusive":false},"com":{"rules":[4],"inclusive":false},"par":{"rules":[31,32],"inclusive":false},"INITIAL":{"rules":[0,1,2,33],"inclusive":true}}; return lexer;})() parser.lexer = lexer; function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser; diff --git a/spec/qunit_spec.js b/spec/qunit_spec.js index f12e44cd4..3de93116a 100644 --- a/spec/qunit_spec.js +++ b/spec/qunit_spec.js @@ -92,6 +92,12 @@ test("most basic", function() { shouldCompileTo("{{foo}}", { foo: "foo" }, "foo"); }); +test("escaping", function() { + shouldCompileTo("\\{{foo}}", { foo: "food" }, "{{foo}}"); + shouldCompileTo("\\\\{{foo}}", { foo: "food" }, "\\food"); + shouldCompileTo("\\\\ {{foo}}", { foo: "food" }, "\\\\ food"); +}); + test("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"); diff --git a/src/handlebars.l b/src/handlebars.l index b32e39c64..cbf048d56 100644 --- a/src/handlebars.l +++ b/src/handlebars.l @@ -3,6 +3,7 @@ %% +"\\\\"/("{{") { yytext = "\\"; return 'CONTENT'; } [^\x00]*?/("{{") { if(yytext.slice(-1) !== "\\") this.begin("mu"); if(yytext.slice(-1) === "\\") yytext = yytext.substr(0,yyleng-1), this.begin("emu"); From fe74d65f2b5d814a2c378394d4b8ec0efcfb45c5 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 6 Apr 2013 14:26:08 -0500 Subject: [PATCH 10/42] isEmpty test --- spec/qunit_spec.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spec/qunit_spec.js b/spec/qunit_spec.js index 3de93116a..10b20aef5 100644 --- a/spec/qunit_spec.js +++ b/spec/qunit_spec.js @@ -1403,3 +1403,18 @@ test('GS-428: Nested if else rendering', function() { shouldCompileTo(succeedingTemplate, [{}, helpers], ' Expected '); shouldCompileTo(failingTemplate, [{}, helpers], ' Expected '); }); + +suite('Utils'); + +test('isEmpty', function() { + equal(Handlebars.Utils.isEmpty(undefined), true); + equal(Handlebars.Utils.isEmpty(null), true); + equal(Handlebars.Utils.isEmpty(false), true); + equal(Handlebars.Utils.isEmpty(''), true); + equal(Handlebars.Utils.isEmpty([]), true); + + equal(Handlebars.Utils.isEmpty(0), false); + equal(Handlebars.Utils.isEmpty([1]), false); + equal(Handlebars.Utils.isEmpty('foo'), false); + equal(Handlebars.Utils.isEmpty({bar: 1}), false); +}); From f4d0092bb836f2c12ddf42dfe6be8e16778ffea5 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 6 Apr 2013 14:42:33 -0500 Subject: [PATCH 11/42] escapeExpression tests --- spec/qunit_spec.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spec/qunit_spec.js b/spec/qunit_spec.js index 10b20aef5..479f64b58 100644 --- a/spec/qunit_spec.js +++ b/spec/qunit_spec.js @@ -1406,6 +1406,19 @@ test('GS-428: Nested if else rendering', function() { suite('Utils'); +test('escapeExpression', function() { + equal(Handlebars.Utils.escapeExpression('foo<&"\'>'), 'foo<&"'>'); + equal(Handlebars.Utils.escapeExpression(new Handlebars.SafeString('foo<&"\'>')), 'foo<&"\'>'); + equal(Handlebars.Utils.escapeExpression(''), ''); + equal(Handlebars.Utils.escapeExpression(undefined), ''); + equal(Handlebars.Utils.escapeExpression(null), ''); + equal(Handlebars.Utils.escapeExpression(false), ''); + + equal(Handlebars.Utils.escapeExpression(0), '0'); + equal(Handlebars.Utils.escapeExpression({}), {}.toString()); + equal(Handlebars.Utils.escapeExpression([]), [].toString()); +}); + test('isEmpty', function() { equal(Handlebars.Utils.isEmpty(undefined), true); equal(Handlebars.Utils.isEmpty(null), true); From 671c07e6992d3094f3c06f2552fe1ab414ddec44 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 6 Apr 2013 14:46:04 -0500 Subject: [PATCH 12/42] Force toString in escapeExpression Fixes #211 --- dist/handlebars.js | 5 +++++ dist/handlebars.runtime.js | 5 +++++ lib/handlebars/utils.js | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/dist/handlebars.js b/dist/handlebars.js index 5bd69b5c8..7942d5e9a 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -825,6 +825,11 @@ Handlebars.Utils = { return ""; } + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = string.toString(); + if(!possible.test(string)) { return string; } return string.replace(badChars, escapeChar); }, diff --git a/dist/handlebars.runtime.js b/dist/handlebars.runtime.js index 4779ad0a3..1c9b9225a 100644 --- a/dist/handlebars.runtime.js +++ b/dist/handlebars.runtime.js @@ -211,6 +211,11 @@ Handlebars.Utils = { return ""; } + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = string.toString(); + if(!possible.test(string)) { return string; } return string.replace(badChars, escapeChar); }, diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js index 85c1a9408..7d9da1741 100644 --- a/lib/handlebars/utils.js +++ b/lib/handlebars/utils.js @@ -47,6 +47,11 @@ Handlebars.Utils = { return ""; } + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = string.toString(); + if(!possible.test(string)) { return string; } return string.replace(badChars, escapeChar); }, From 31aaa30fcd6ac0d39b41fe5e46ed00480c1d168f Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 6 Apr 2013 15:28:18 -0500 Subject: [PATCH 13/42] Rebuild --- dist/handlebars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/handlebars.js b/dist/handlebars.js index 7942d5e9a..b254c7e5d 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -632,7 +632,7 @@ case 33: return 5; break; } }; -lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-/]+)/,/^(?:$)/]; +lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[}/ ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$:-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-/]+)/,/^(?:$)/]; lexer.conditions = {"mu":{"rules":[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,33],"inclusive":false},"emu":{"rules":[3],"inclusive":false},"com":{"rules":[4],"inclusive":false},"par":{"rules":[31,32],"inclusive":false},"INITIAL":{"rules":[0,1,2,33],"inclusive":true}}; return lexer;})() parser.lexer = lexer; From e33d9b4dcf1556b6f1037e00a665d029f7b0e425 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 6 Apr 2013 15:28:27 -0500 Subject: [PATCH 14/42] Add test case for GH-458 --- spec/qunit_spec.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/qunit_spec.js b/spec/qunit_spec.js index 479f64b58..9832d606c 100644 --- a/spec/qunit_spec.js +++ b/spec/qunit_spec.js @@ -1404,6 +1404,10 @@ test('GS-428: Nested if else rendering', function() { shouldCompileTo(failingTemplate, [{}, helpers], ' Expected '); }); +test('GH-458: Scoped this identifier', function() { + shouldCompileTo('{{./foo}}', {foo: 'bar'}, 'bar'); +}); + suite('Utils'); test('escapeExpression', function() { From bee0facaca63d0ce0775be2e1c679c0d28fec949 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 6 Apr 2013 15:49:13 -0500 Subject: [PATCH 15/42] Rebuild --- dist/handlebars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/handlebars.js b/dist/handlebars.js index b254c7e5d..afdb0b990 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -632,7 +632,7 @@ case 33: return 5; break; } }; -lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[}/ ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$:-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-/]+)/,/^(?:$)/]; +lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[}/ ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$:-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-\/]+)/,/^(?:$)/]; lexer.conditions = {"mu":{"rules":[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,33],"inclusive":false},"emu":{"rules":[3],"inclusive":false},"com":{"rules":[4],"inclusive":false},"par":{"rules":[31,32],"inclusive":false},"INITIAL":{"rules":[0,1,2,33],"inclusive":true}}; return lexer;})() parser.lexer = lexer; From 4d66d0c0a688206c1b637b9d02da4a77eb5d1f71 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 6 Apr 2013 16:42:24 -0500 Subject: [PATCH 16/42] Escape unicode newlines in string literals Fixes #375 --- dist/handlebars.js | 4 +++- lib/handlebars/compiler/compiler.js | 4 +++- spec/qunit_spec.js | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dist/handlebars.js b/dist/handlebars.js index afdb0b990..d7f140ee7 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -1971,7 +1971,9 @@ JavaScriptCompiler.prototype = { .replace(/\\/g, '\\\\') .replace(/"/g, '\\"') .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') + '"'; + .replace(/\r/g, '\\r') + .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 + .replace(/\u2029/g, '\\u2029') + '"'; }, setupHelper: function(paramSize, name, missingParams) { diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index 196ba18bb..b0280761d 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -1130,7 +1130,9 @@ JavaScriptCompiler.prototype = { .replace(/\\/g, '\\\\') .replace(/"/g, '\\"') .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') + '"'; + .replace(/\r/g, '\\r') + .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 + .replace(/\u2029/g, '\\u2029') + '"'; }, setupHelper: function(paramSize, name, missingParams) { diff --git a/spec/qunit_spec.js b/spec/qunit_spec.js index 9832d606c..6c44e4e0d 100644 --- a/spec/qunit_spec.js +++ b/spec/qunit_spec.js @@ -1408,6 +1408,10 @@ test('GH-458: Scoped this identifier', function() { shouldCompileTo('{{./foo}}', {foo: 'bar'}, 'bar'); }); +test('GH-375: Unicode line terminators', function() { + shouldCompileTo('\u2028', {}, '\u2028'); +}); + suite('Utils'); test('escapeExpression', function() { From ff32b4e2adbac536c69cb1c87071b8f98c09e50a Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 6 Apr 2013 23:14:29 -0500 Subject: [PATCH 17/42] Escape passed regex --- bin/handlebars | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/handlebars b/bin/handlebars index f0986a0bc..61886dac2 100755 --- a/bin/handlebars +++ b/bin/handlebars @@ -116,7 +116,8 @@ if (argv.known) { } // Build file extension pattern -var extension = new RegExp('\\.' + argv.extension + '$'); +var extension = argv.extension.replace(/[\\^$*+?.():=!|{}\-\[\]]/g, function(arg) { return '\\' + arg; }); +extension = new RegExp('\\.' + extension + '$'); var output = []; if (!argv.simple) { From 12d68caa58b21c847c00818a811782a85ecd5266 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 6 Apr 2013 23:17:39 -0500 Subject: [PATCH 18/42] Allow compilation of empty string Fixes #461 --- dist/handlebars.js | 4 ++-- lib/handlebars/compiler/compiler.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/handlebars.js b/dist/handlebars.js index d7f140ee7..cce5473ca 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -2079,7 +2079,7 @@ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) { }; Handlebars.precompile = function(input, options) { - if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { + if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input); } @@ -2093,7 +2093,7 @@ Handlebars.precompile = function(input, options) { }; Handlebars.compile = function(input, options) { - if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { + if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input); } diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index b0280761d..b31d92b2d 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -1238,7 +1238,7 @@ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) { }; Handlebars.precompile = function(input, options) { - if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { + if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input); } @@ -1252,7 +1252,7 @@ Handlebars.precompile = function(input, options) { }; Handlebars.compile = function(input, options) { - if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { + if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input); } From f6ff5c648b6e576d8b6f48ea2a6291dcc6a9e5be Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 6 Apr 2013 23:23:40 -0500 Subject: [PATCH 19/42] Restore knownHelpersOnly throw Fixes #302 --- lib/handlebars/compiler/compiler.js | 2 +- spec/qunit_spec.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index b31d92b2d..dc17020ca 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -272,7 +272,7 @@ Compiler.prototype = { if (this.options.knownHelpers[name]) { this.opcode('invokeKnownHelper', params.length, name); - } else if (this.knownHelpersOnly) { + } else if (this.options.knownHelpersOnly) { throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name); } else { this.opcode('invokeHelper', params.length, name); diff --git a/spec/qunit_spec.js b/spec/qunit_spec.js index 6c44e4e0d..fefb8ecd9 100644 --- a/spec/qunit_spec.js +++ b/spec/qunit_spec.js @@ -709,6 +709,11 @@ test("Functions are bound to the context in knownHelpers only mode", function() var result = template({foo: function() { return this.bar; }, bar: 'bar'}); equal(result, "bar", "'bar' should === '" + result); }); +test("Unknown helper call in knownHelpers only mode should throw", function() { + shouldThrow(function() { + CompilerContext.compile("{{typeof hello}}", {knownHelpersOnly: true}); + }, Error, 'specified knownHelpersOnly'); +}); suite("blockHelperMissing"); From 381c113d66bfe1de3ad88cbde9d247f1d5caff40 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 7 Apr 2013 12:41:55 -0500 Subject: [PATCH 20/42] Rebuild --- dist/handlebars.js | 40 +++++++++++++++++++------------------- dist/handlebars.runtime.js | 31 ++++++++++++++++------------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/dist/handlebars.js b/dist/handlebars.js index cce5473ca..50172b79b 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -30,11 +30,12 @@ var Handlebars = {}; // lib/handlebars/base.js Handlebars.VERSION = "1.0.0-rc.3"; -Handlebars.COMPILER_REVISION = 2; +Handlebars.COMPILER_REVISION = 3; Handlebars.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' + 2: '== 1.0.0-rc.3', + 3: '>= 1.0.0-rc.4' }; Handlebars.helpers = {}; @@ -1113,7 +1114,7 @@ Compiler.prototype = { if (this.options.knownHelpers[name]) { this.opcode('invokeKnownHelper', params.length, name); - } else if (this.knownHelpersOnly) { + } else if (this.options.knownHelpersOnly) { throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name); } else { this.opcode('invokeHelper', params.length, name); @@ -1834,12 +1835,7 @@ JavaScriptCompiler.prototype = { else { programParams.push("depth" + (depth - 1)); } } - if(depths.length === 0) { - return "self.program(" + programParams.join(", ") + ")"; - } else { - programParams.shift(); - return "self.programWithDepth(" + programParams.join(", ") + ")"; - } + return (depths.length === 0 ? "self.program(" : "self.programWithDepth(") + programParams.join(", ") + ")"; }, register: function(name, val) { @@ -2131,13 +2127,11 @@ Handlebars.VM = { program: function(i, fn, data) { var programWrapper = this.programs[i]; if(data) { - return Handlebars.VM.program(fn, data); - } else if(programWrapper) { - return programWrapper; - } else { - programWrapper = this.programs[i] = Handlebars.VM.program(fn); - return programWrapper; + programWrapper = Handlebars.VM.program(i, fn, data); + } else if (!programWrapper) { + programWrapper = this.programs[i] = Handlebars.VM.program(i, fn); } + return programWrapper; }, programWithDepth: Handlebars.VM.programWithDepth, noop: Handlebars.VM.noop, @@ -2169,21 +2163,27 @@ Handlebars.VM = { }; }, - programWithDepth: function(fn, data, $depth) { - var args = Array.prototype.slice.call(arguments, 2); + programWithDepth: function(i, fn, data /*, $depth */) { + var args = Array.prototype.slice.call(arguments, 3); - return function(context, options) { + var program = function(context, options) { options = options || {}; return fn.apply(this, [context, options.data || data].concat(args)); }; + program.program = i; + program.depth = args.length; + return program; }, - program: function(fn, data) { - return function(context, options) { + program: function(i, fn, data) { + var program = function(context, options) { options = options || {}; return fn(context, options.data || data); }; + program.program = i; + program.depth = 0; + return program; }, noop: function() { return ""; }, invokePartial: function(partial, name, context, helpers, partials, data) { diff --git a/dist/handlebars.runtime.js b/dist/handlebars.runtime.js index 1c9b9225a..00c0b2fd9 100644 --- a/dist/handlebars.runtime.js +++ b/dist/handlebars.runtime.js @@ -30,11 +30,12 @@ var Handlebars = {}; // lib/handlebars/base.js Handlebars.VERSION = "1.0.0-rc.3"; -Handlebars.COMPILER_REVISION = 2; +Handlebars.COMPILER_REVISION = 3; Handlebars.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' + 2: '== 1.0.0-rc.3', + 3: '>= 1.0.0-rc.4' }; Handlebars.helpers = {}; @@ -243,13 +244,11 @@ Handlebars.VM = { program: function(i, fn, data) { var programWrapper = this.programs[i]; if(data) { - return Handlebars.VM.program(fn, data); - } else if(programWrapper) { - return programWrapper; - } else { - programWrapper = this.programs[i] = Handlebars.VM.program(fn); - return programWrapper; + programWrapper = Handlebars.VM.program(i, fn, data); + } else if (!programWrapper) { + programWrapper = this.programs[i] = Handlebars.VM.program(i, fn); } + return programWrapper; }, programWithDepth: Handlebars.VM.programWithDepth, noop: Handlebars.VM.noop, @@ -281,21 +280,27 @@ Handlebars.VM = { }; }, - programWithDepth: function(fn, data, $depth) { - var args = Array.prototype.slice.call(arguments, 2); + programWithDepth: function(i, fn, data /*, $depth */) { + var args = Array.prototype.slice.call(arguments, 3); - return function(context, options) { + var program = function(context, options) { options = options || {}; return fn.apply(this, [context, options.data || data].concat(args)); }; + program.program = i; + program.depth = args.length; + return program; }, - program: function(fn, data) { - return function(context, options) { + program: function(i, fn, data) { + var program = function(context, options) { options = options || {}; return fn(context, options.data || data); }; + program.program = i; + program.depth = 0; + return program; }, noop: function() { return ""; }, invokePartial: function(partial, name, context, helpers, partials, data) { From 73f2016a6a5e7ce11077e44ec3288e0dac2df7c9 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 7 Apr 2013 16:50:57 -0500 Subject: [PATCH 21/42] Remove FULL_CONTEXT from spec_helper --- spec/parser_spec.rb | 2 +- spec/spec_helper.rb | 19 +------------------ 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index 999702752..293fe1f74 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -421,7 +421,7 @@ def path(*parts) end it "can pass through an already-compiled AST via compile/precompile" do - @context = Handlebars::Spec::FULL_CONTEXT + @context = Handlebars::Spec::CONTEXT code = 'Handlebars.compile(new Handlebars.AST.ProgramNode([ new Handlebars.AST.ContentNode("Hello")]))();' @context.eval(code).should == "Hello" diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e79415ad2..eb2f26afd 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -87,7 +87,7 @@ def self.js_load(context, file) end CompilerContext["compileWithPartial"] = proc do |this, *args| template, options = args[0], args[1] || nil - FULL_CONTEXT["Handlebars"]["compile"].call(template, options); + context["Handlebars"]["compile"].call(template, options); end end @@ -116,23 +116,6 @@ def self.js_load(context, file) end end end - - FULL_CONTEXT = V8::Context.new - FULL_CONTEXT.instance_eval do |context| - Handlebars::Spec.load_helpers(context); - - Handlebars::Spec.js_load(context, 'dist/handlebars.js'); - - context["Handlebars"]["logger"]["level"] = ENV["DEBUG_JS"] ? context["Handlebars"]["logger"][ENV["DEBUG_JS"]] : 4 - - context["Handlebars"]["logger"]["log"] = proc do |this, level, str| - logger_level = context["Handlebars"]["logger"]["level"].to_i - - if logger_level <= level - puts str - end - end - end end end From 4429ffa9f37620afb211d15480545bd12b54bba5 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 7 Apr 2013 18:04:51 -0500 Subject: [PATCH 22/42] Allow multiple partial and helper registration Fixes #369 --- dist/handlebars.js | 29 ++++++++++++++++++++++++----- dist/handlebars.runtime.js | 29 ++++++++++++++++++++++++----- lib/handlebars/base.js | 21 ++++++++++++++++----- lib/handlebars/utils.js | 8 ++++++++ spec/qunit_spec.js | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 104 insertions(+), 15 deletions(-) diff --git a/dist/handlebars.js b/dist/handlebars.js index 50172b79b..828bbee5c 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -41,13 +41,26 @@ Handlebars.REVISION_CHANGES = { Handlebars.helpers = {}; Handlebars.partials = {}; +var toString = Object.prototype.toString, + functionType = '[object Function]', + objectType = '[object Object]'; + Handlebars.registerHelper = function(name, fn, inverse) { - if(inverse) { fn.not = inverse; } - this.helpers[name] = fn; + if (toString.call(name) === objectType) { + if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); } + Handlebars.Utils.extend(this.helpers, name); + } else { + if (inverse) { fn.not = inverse; } + this.helpers[name] = fn; + } }; Handlebars.registerPartial = function(name, str) { - this.partials[name] = str; + if (toString.call(name) === objectType) { + Handlebars.Utils.extend(this.partials, name); + } else { + this.partials[name] = str; + } }; Handlebars.registerHelper('helperMissing', function(arg) { @@ -58,8 +71,6 @@ Handlebars.registerHelper('helperMissing', function(arg) { } }); -var toString = Object.prototype.toString, functionType = "[object Function]"; - Handlebars.registerHelper('blockHelperMissing', function(context, options) { var inverse = options.inverse || function() {}, fn = options.fn; @@ -818,6 +829,14 @@ var escapeChar = function(chr) { }; Handlebars.Utils = { + extend: function(obj, value) { + for(var key in value) { + if(value.hasOwnProperty(key)) { + obj[key] = value[key]; + } + } + }, + escapeExpression: function(string) { // don't escape SafeStrings, since they're already safe if (string instanceof Handlebars.SafeString) { diff --git a/dist/handlebars.runtime.js b/dist/handlebars.runtime.js index 00c0b2fd9..b6ba8a51f 100644 --- a/dist/handlebars.runtime.js +++ b/dist/handlebars.runtime.js @@ -41,13 +41,26 @@ Handlebars.REVISION_CHANGES = { Handlebars.helpers = {}; Handlebars.partials = {}; +var toString = Object.prototype.toString, + functionType = '[object Function]', + objectType = '[object Object]'; + Handlebars.registerHelper = function(name, fn, inverse) { - if(inverse) { fn.not = inverse; } - this.helpers[name] = fn; + if (toString.call(name) === objectType) { + if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); } + Handlebars.Utils.extend(this.helpers, name); + } else { + if (inverse) { fn.not = inverse; } + this.helpers[name] = fn; + } }; Handlebars.registerPartial = function(name, str) { - this.partials[name] = str; + if (toString.call(name) === objectType) { + Handlebars.Utils.extend(this.partials, name); + } else { + this.partials[name] = str; + } }; Handlebars.registerHelper('helperMissing', function(arg) { @@ -58,8 +71,6 @@ Handlebars.registerHelper('helperMissing', function(arg) { } }); -var toString = Object.prototype.toString, functionType = "[object Function]"; - Handlebars.registerHelper('blockHelperMissing', function(context, options) { var inverse = options.inverse || function() {}, fn = options.fn; @@ -204,6 +215,14 @@ var escapeChar = function(chr) { }; Handlebars.Utils = { + extend: function(obj, value) { + for(var key in value) { + if(value.hasOwnProperty(key)) { + obj[key] = value[key]; + } + } + }, + escapeExpression: function(string) { // don't escape SafeStrings, since they're already safe if (string instanceof Handlebars.SafeString) { diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index e6dbc1e33..5e7ea0e71 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -18,13 +18,26 @@ Handlebars.REVISION_CHANGES = { Handlebars.helpers = {}; Handlebars.partials = {}; +var toString = Object.prototype.toString, + functionType = '[object Function]', + objectType = '[object Object]'; + Handlebars.registerHelper = function(name, fn, inverse) { - if(inverse) { fn.not = inverse; } - this.helpers[name] = fn; + if (toString.call(name) === objectType) { + if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); } + Handlebars.Utils.extend(this.helpers, name); + } else { + if (inverse) { fn.not = inverse; } + this.helpers[name] = fn; + } }; Handlebars.registerPartial = function(name, str) { - this.partials[name] = str; + if (toString.call(name) === objectType) { + Handlebars.Utils.extend(this.partials, name); + } else { + this.partials[name] = str; + } }; Handlebars.registerHelper('helperMissing', function(arg) { @@ -35,8 +48,6 @@ Handlebars.registerHelper('helperMissing', function(arg) { } }); -var toString = Object.prototype.toString, functionType = "[object Function]"; - Handlebars.registerHelper('blockHelperMissing', function(context, options) { var inverse = options.inverse || function() {}, fn = options.fn; diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js index 7d9da1741..dffc477b9 100644 --- a/lib/handlebars/utils.js +++ b/lib/handlebars/utils.js @@ -39,6 +39,14 @@ var escapeChar = function(chr) { }; Handlebars.Utils = { + extend: function(obj, value) { + for(var key in value) { + if(value.hasOwnProperty(key)) { + obj[key] = value[key]; + } + } + }, + escapeExpression: function(string) { // don't escape SafeStrings, since they're already safe if (string instanceof Handlebars.SafeString) { diff --git a/spec/qunit_spec.js b/spec/qunit_spec.js index fefb8ecd9..1fb45a5c1 100644 --- a/spec/qunit_spec.js +++ b/spec/qunit_spec.js @@ -492,6 +492,27 @@ test("the helpers hash is available is nested contexts", function() { "helpers hash is available in nested contexts."); }); +test("Multiple global helper registration", function() { + var helpers = Handlebars.helpers; + try { + Handlebars.helpers = {}; + Handlebars.registerHelper({ + 'if': helpers['if'], + world: function() { return "world!"; }, + test_helper: function() { return 'found it!'; } + }); + + shouldCompileTo( + "{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}", + [{cruel: "cruel"}], + "found it! Goodbye cruel world!!"); + } finally { + if (helpers) { + Handlebars.helpers = helpers; + } + } +}); + suite("partials"); test("basic partials", function() { @@ -556,6 +577,17 @@ test("Partials with slash paths", function() { shouldCompileToWithPartials(string, [hash, {}, {'shared/dude':dude}], true, "Dudes: Jeepers", "Partials can use literal paths"); }); +test("Multiple partial registration", function() { + Handlebars.registerPartial({ + 'shared/dude': '{{name}}', + global_test: '{{another_dude}}' + }); + + 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"); +}); + test("Partials with integer path", function() { var string = "Dudes: {{> 404}}"; var dude = "{{name}}"; From 85a21f2359da7ad9e844996fbf3c2df5eea88459 Mon Sep 17 00:00:00 2001 From: James Maroney Date: Mon, 8 Apr 2013 10:36:43 -0400 Subject: [PATCH 23/42] If building AMD modules, and only one template is being compiled, return the compiled template from the AMD module --- bin/handlebars | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/handlebars b/bin/handlebars index 61886dac2..1e46a35f4 100755 --- a/bin/handlebars +++ b/bin/handlebars @@ -168,8 +168,10 @@ function processTemplate(template, root) { if (argv.simple) { output.push(handlebars.precompile(data, options) + '\n'); } else if (argv.partial) { + if(argv.amd && argv._.length == 1){ output.push('return '); } output.push('Handlebars.partials[\'' + template + '\'] = template(' + handlebars.precompile(data, options) + ');\n'); } else { + if(argv.amd && argv._.length == 1){ output.push('return '); } output.push('templates[\'' + template + '\'] = template(' + handlebars.precompile(data, options) + ');\n'); } } From ca576c27fc313b63d526da49a57a0a27e10d9e97 Mon Sep 17 00:00:00 2001 From: James Maroney Date: Mon, 8 Apr 2013 10:37:18 -0400 Subject: [PATCH 24/42] If building AMD module and compiling multiple templates, return the full templates (or partials) hash from the AMD module --- bin/handlebars | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bin/handlebars b/bin/handlebars index 1e46a35f4..d605e74db 100755 --- a/bin/handlebars +++ b/bin/handlebars @@ -184,6 +184,13 @@ argv._.forEach(function(template) { // Output the content if (!argv.simple) { if (argv.amd) { + if(argv._.length > 1){ + if(argv.partial){ + output.push('return Handlebars.partials;\n'); + } else { + output.push('return templates;\n'); + } + } output.push('});'); } else if (!argv.commonjs) { output.push('})();'); From 5c9aa9e4d629a59c2427be5b96e18e2c016afbce Mon Sep 17 00:00:00 2001 From: DevinClark Date: Mon, 8 Apr 2013 12:28:13 -0500 Subject: [PATCH 25/42] Added a component.json file for Twitter's Bower package manager. See [https://github.com/twitter/bower#defining-a-package](Defining a package) for more information about how the file was generated. --- component.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 component.json diff --git a/component.json b/component.json new file mode 100644 index 000000000..320a12b56 --- /dev/null +++ b/component.json @@ -0,0 +1,9 @@ +{ + "name": "handlebars.js", + "version": "1.0.0-rc.3", + "main": "dist/handlebars.js", + "ignore": [ + "node_modules", + "components" + ] +} \ No newline at end of file From d8d2a6a1d2315f10b1774de7982bcf1c3cc6742b Mon Sep 17 00:00:00 2001 From: Ian Young Date: Tue, 16 Apr 2013 16:32:40 -0700 Subject: [PATCH 26/42] Change download link in install instructions The install instructions in the readme were still pointing to the GitHub downloads page, which is deprecated and out of date. Updated to point to the official site, which has a big download button. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 0b338e829..c35426a28 100644 --- a/README.markdown +++ b/README.markdown @@ -10,7 +10,7 @@ Checkout the official Handlebars docs site at [http://www.handlebarsjs.com](http Installing ---------- -Installing Handlebars is easy. Simply [download the package from GitHub](https://github.com/wycats/handlebars.js/archives/master) and add it to your web pages (you should usually use the most recent version). +Installing Handlebars is easy. Simply download the package [from the official site](http://handlebarsjs.com/) and add it to your web pages (you should usually use the most recent version). Usage ----- From 06e593d32e3446bc10ee13e4fe8a2b79b05ba2ba Mon Sep 17 00:00:00 2001 From: Giles Bowkett Date: Thu, 25 Apr 2013 14:44:52 -0700 Subject: [PATCH 27/42] paragraph width --- README.markdown | 110 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 81 insertions(+), 29 deletions(-) diff --git a/README.markdown b/README.markdown index c35426a28..e787e59fa 100644 --- a/README.markdown +++ b/README.markdown @@ -3,20 +3,30 @@ Handlebars.js ============= -Handlebars.js is an extension to the [Mustache templating language](http://mustache.github.com/) created by Chris Wanstrath. Handlebars.js and Mustache are both logicless templating languages that keep the view and the code separated like we all know they should be. +Handlebars.js is an extension to the [Mustache templating +language](http://mustache.github.com/) created by Chris Wanstrath. +Handlebars.js and Mustache are both logicless templating languages that +keep the view and the code separated like we all know they should be. -Checkout the official Handlebars docs site at [http://www.handlebarsjs.com](http://www.handlebarsjs.com). +Checkout the official Handlebars docs site at +[http://www.handlebarsjs.com](http://www.handlebarsjs.com). Installing ---------- -Installing Handlebars is easy. Simply download the package [from the official site](http://handlebarsjs.com/) and add it to your web pages (you should usually use the most recent version). +Installing Handlebars is easy. Simply download the package [from the +official site](http://handlebarsjs.com/) and add it to your web pages +(you should usually use the most recent version). Usage ----- -In general, the syntax of Handlebars.js templates is a superset of Mustache templates. For basic syntax, check out the [Mustache manpage](http://mustache.github.com/mustache.5.html). +In general, the syntax of Handlebars.js templates is a superset +of Mustache templates. For basic syntax, check out the [Mustache +manpage](http://mustache.github.com/mustache.5.html). -Once you have a template, use the Handlebars.compile method to compile the template into a function. The generated function takes a context argument, which will be used to render the template. +Once you have a template, use the Handlebars.compile method to compile +the template into a function. The generated function takes a context +argument, which will be used to render the template. ```js var source = "

Hello, my name is {{name}}. I am from {{hometown}}. I have " + @@ -75,25 +85,34 @@ To explicitly *not* escape the contents, use the triple-mustache Differences Between Handlebars.js and Mustache ---------------------------------------------- -Handlebars.js adds a couple of additional features to make writing templates easier and also changes a tiny detail of how partials work. +Handlebars.js adds a couple of additional features to make writing +templates easier and also changes a tiny detail of how partials work. ### Paths -Handlebars.js supports an extended expression syntax that we call paths. Paths are made up of typical expressions and . characters. Expressions allow you to not only display data from the current context, but to display data from contexts that are descendents and ancestors of the current context. +Handlebars.js supports an extended expression syntax that we call paths. +Paths are made up of typical expressions and . characters. Expressions +allow you to not only display data from the current context, but to +display data from contexts that are descendents and ancestors of the +current context. -To display data from descendent contexts, use the `.` character. So, for example, if your data were structured like: +To display data from descendent contexts, use the `.` character. So, for +example, if your data were structured like: ```js var data = {"person": { "name": "Alan" }, company: {"name": "Rad, Inc." } }; ``` -you could display the person's name from the top-level context with the following expression: +you could display the person's name from the top-level context with the +following expression: ``` {{person.name}} ``` -You can backtrack using `../`. For example, if you've already traversed into the person object you could still display the company's name with an expression like `{{../company.name}}`, so: +You can backtrack using `../`. For example, if you've already traversed +into the person object you could still display the company's name with +an expression like `{{../company.name}}`, so: ``` {{#person}}{{name}} - {{../company.name}}{{/person}} @@ -134,7 +153,9 @@ gets passed to the helper function. ### Block Helpers -Handlebars.js also adds the ability to define block helpers. Block helpers are functions that can be called from anywhere in the template. Here's an example: +Handlebars.js also adds the ability to define block helpers. Block +helpers are functions that can be called from anywhere in the template. +Here's an example: ```js var source = "

    {{#people}}
  • {{#link}}{{name}}{{/link}}
  • {{/people}}
"; @@ -156,7 +177,12 @@ template(data); // ``` -Whenever the block helper is called it is given two parameters, the argument that is passed to the helper, or the current context if no argument is passed and the compiled contents of the block. Inside of the block helper the value of `this` is the current context, wrapped to include a method named `__get__` that helps translate paths into values within the helpers. +Whenever the block helper is called it is given two parameters, the +argument that is passed to the helper, or the current context if no +argument is passed and the compiled contents of the block. Inside of +the block helper the value of `this` is the current context, wrapped to +include a method named `__get__` that helps translate paths into values +within the helpers. ### Partials @@ -229,13 +255,15 @@ Options: -r, --root Template root. Base value that will be stripped from template names. [string] -If using the precompiler's normal mode, the resulting templates will be stored -to the `Handlebars.templates` object using the relative template name sans the -extension. These templates may be executed in the same manner as templates. +If using the precompiler's normal mode, the resulting templates will be +stored to the `Handlebars.templates` object using the relative template +name sans the extension. These templates may be executed in the same +manner as templates. -If using the simple mode the precompiler will generate a single javascript method. -To execute this method it must be passed to the using the `Handlebars.template` -method and the resulting object may be as normal. +If using the simple mode the precompiler will generate a single +javascript method. To execute this method it must be passed to the using +the `Handlebars.template` method and the resulting object may be as +normal. ### Optimizations @@ -252,7 +280,15 @@ method and the resulting object may be as normal. Performance ----------- -In a rough performance test, precompiled Handlebars.js templates (in the original version of Handlebars.js) rendered in about half the time of Mustache templates. It would be a shame if it were any other way, since they were precompiled, but the difference in architecture does have some big performance advantages. Justin Marney, a.k.a. [gotascii](http://github.com/gotascii), confirmed that with an [independent test](http://sorescode.com/2010/09/12/benchmarks.html). The rewritten Handlebars (current version) is faster than the old version, and we will have some benchmarks in the near future. +In a rough performance test, precompiled Handlebars.js templates (in +the original version of Handlebars.js) rendered in about half the +time of Mustache templates. It would be a shame if it were any other +way, since they were precompiled, but the difference in architecture +does have some big performance advantages. Justin Marney, a.k.a. +[gotascii](http://github.com/gotascii), confirmed that with an +[independent test](http://sorescode.com/2010/09/12/benchmarks.html). The +rewritten Handlebars (current version) is faster than the old version, +and we will have some benchmarks in the near future. Building @@ -288,13 +324,19 @@ Known Issues Handlebars in the Wild ----------------- -* [jblotus](http://github.com/jblotus) created [http://tryhandlebarsjs.com](http://tryhandlebarsjs.com) for anyone who would -like to try out Handlebars.js in their browser. -* Don Park wrote an Express.js view engine adapter for Handlebars.js called [hbs](http://github.com/donpark/hbs). -* [sammy.js](http://github.com/quirkey/sammy) by Aaron Quint, a.k.a. quirkey, supports Handlebars.js as one of its template plugins. -* [SproutCore](http://www.sproutcore.com) uses Handlebars.js as its main templating engine, extending it with automatic data binding support. -* [Ember.js](http://www.emberjs.com) makes Handlebars.js the primary way to structure your views, also with automatic data binding support. -* Les Hill (@leshill) wrote a Rails Asset Pipeline gem named [handlebars_assets](http://github.com/leshill/handlebars_assets). +* [jblotus](http://github.com/jblotus) created +[http://tryhandlebarsjs.com](http://tryhandlebarsjs.com) for anyone who +would like to try out Handlebars.js in their browser. +* Don Park wrote an Express.js view engine adapter for Handlebars.js +called [hbs](http://github.com/donpark/hbs). +* [sammy.js](http://github.com/quirkey/sammy) by Aaron Quint, a.k.a. +quirkey, supports Handlebars.js as one of its template plugins. +* [SproutCore](http://www.sproutcore.com) uses Handlebars.js as its main +templating engine, extending it with automatic data binding support. +* [Ember.js](http://www.emberjs.com) makes Handlebars.js the primary way +to structure your views, also with automatic data binding support. +* Les Hill (@leshill) wrote a Rails Asset Pipeline gem named +[handlebars_assets](http://github.com/leshill/handlebars_assets). Helping Out ----------- @@ -306,12 +348,22 @@ To build Handlebars.js you'll need a few things installed. * therubyracer, for running tests - `gem install therubyracer` * rspec, for running tests - `gem install rspec` -There's a Gemfile in the repo, so you can run `bundle` to install rspec and therubyracer if you've got bundler installed. +There's a Gemfile in the repo, so you can run `bundle` to install rspec +and therubyracer if you've got bundler installed. -To build Handlebars.js from scratch, you'll want to run `rake compile` in the root of the project. That will build Handlebars and output the results to the dist/ folder. To run tests, run `rake spec`. You can also run our set of benchmarks with `rake bench`. +To build Handlebars.js from scratch, you'll want to run `rake compile` +in the root of the project. That will build Handlebars and output the +results to the dist/ folder. To run tests, run `rake spec`. You can also +run our set of benchmarks with `rake bench`. -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). Feel free to contact commondream or wycats through GitHub with any other questions or feature requests. To submit changes fork the project and send a pull request. +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). +Feel free to contact commondream or wycats through GitHub with any other +questions or feature requests. To submit changes fork the project and +send a pull request. License ------- Handlebars.js is released under the MIT license. + From fc52a65c701306870bec4260e1b8abb599bc2c8f Mon Sep 17 00:00:00 2001 From: DevinClark Date: Thu, 25 Apr 2013 21:05:21 -0500 Subject: [PATCH 28/42] Changed component.json to bower.json per Bower 0.9.0 update. --- component.json => bower.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename component.json => bower.json (100%) diff --git a/component.json b/bower.json similarity index 100% rename from component.json rename to bower.json From 18798a75460e7b856972fd18a0a4c64e6f299cf8 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 28 Apr 2013 13:53:01 -0500 Subject: [PATCH 29/42] Adjust formatting of bullet list --- README.markdown | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/README.markdown b/README.markdown index e787e59fa..51c4b1d27 100644 --- a/README.markdown +++ b/README.markdown @@ -324,19 +324,18 @@ Known Issues Handlebars in the Wild ----------------- -* [jblotus](http://github.com/jblotus) created -[http://tryhandlebarsjs.com](http://tryhandlebarsjs.com) for anyone who -would like to try out Handlebars.js in their browser. -* Don Park wrote an Express.js view engine adapter for Handlebars.js -called [hbs](http://github.com/donpark/hbs). -* [sammy.js](http://github.com/quirkey/sammy) by Aaron Quint, a.k.a. -quirkey, supports Handlebars.js as one of its template plugins. +* [jblotus](http://github.com/jblotus) created [http://tryhandlebarsjs.com](http://tryhandlebarsjs.com) + for anyone who would like to try out Handlebars.js in their browser. +* Don Park wrote an Express.js view engine adapter for Handlebars.js called + [hbs](http://github.com/donpark/hbs). +* [sammy.js](http://github.com/quirkey/sammy) by Aaron Quint, a.k.a. quirkey, + supports Handlebars.js as one of its template plugins. * [SproutCore](http://www.sproutcore.com) uses Handlebars.js as its main -templating engine, extending it with automatic data binding support. -* [Ember.js](http://www.emberjs.com) makes Handlebars.js the primary way -to structure your views, also with automatic data binding support. + templating engine, extending it with automatic data binding support. +* [Ember.js](http://www.emberjs.com) makes Handlebars.js the primary way to + structure your views, also with automatic data binding support. * Les Hill (@leshill) wrote a Rails Asset Pipeline gem named -[handlebars_assets](http://github.com/leshill/handlebars_assets). + handlebars_assets](http://github.com/leshill/handlebars_assets). Helping Out ----------- From ef325733bb45d0dd15a5c30d3b4c4ff6d2175340 Mon Sep 17 00:00:00 2001 From: Utkarsh Sengar Date: Mon, 2 Apr 2012 13:47:58 -0700 Subject: [PATCH 30/42] Added link to a gist for loading handlebars templates (sync and async) in README. --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 51c4b1d27..1cba64689 100644 --- a/README.markdown +++ b/README.markdown @@ -336,6 +336,7 @@ Handlebars in the Wild structure your views, also with automatic data binding support. * Les Hill (@leshill) wrote a Rails Asset Pipeline gem named handlebars_assets](http://github.com/leshill/handlebars_assets). +* [Gist about Synchronous and asynchronous loading of external handlebars templates](https://gist.github.com/2287070) Helping Out ----------- From 344bb9092dd7030f3625bb5a4c7a7a487126c25b Mon Sep 17 00:00:00 2001 From: MikeMayer Date: Wed, 1 May 2013 09:52:55 -0700 Subject: [PATCH 31/42] Create handlebars.js.nuspec for inclusion in NuGet Added a .nuspec file for those people who use Visual Studio and NuGet and might want to use handlebars.js deployed from NuGet in their application. --- handlebars.js.nuspec | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 handlebars.js.nuspec diff --git a/handlebars.js.nuspec b/handlebars.js.nuspec new file mode 100644 index 000000000..f43d22aae --- /dev/null +++ b/handlebars.js.nuspec @@ -0,0 +1,14 @@ + + + + handlebars.js + 1.0.10 + handlebars.js Authors + https://github.com/wycats/handlebars.js/blob/master/LICENSE + https://github.com/wycats/handlebars.js/ + false + Extension of the Mustache logicless template language + + handlebars mustache template html + + From 8a5705a2536175f0ff9fde65c9e90c6e6bececef Mon Sep 17 00:00:00 2001 From: MikeMayer Date: Wed, 1 May 2013 09:58:17 -0700 Subject: [PATCH 32/42] Explicitly only include the handlebars.js from the dist folder --- handlebars.js.nuspec | 3 +++ 1 file changed, 3 insertions(+) diff --git a/handlebars.js.nuspec b/handlebars.js.nuspec index f43d22aae..e0d00edfd 100644 --- a/handlebars.js.nuspec +++ b/handlebars.js.nuspec @@ -11,4 +11,7 @@ handlebars mustache template html + + + From 090ee7c59a1fd24a1d9f806667e78bd8b5711a1f Mon Sep 17 00:00:00 2001 From: Tommy Messbauer Date: Thu, 9 May 2013 17:17:34 -0500 Subject: [PATCH 33/42] added local pointer to handlerbars.utils to allow this to browserify properly for IE --- lib/handlebars/utils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js index dffc477b9..1e0e4c902 100644 --- a/lib/handlebars/utils.js +++ b/lib/handlebars/utils.js @@ -1,5 +1,7 @@ exports.attach = function(Handlebars) { +var toString = Object.prototype.toString; + // BEGIN(BROWSER) var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; From 44ae572e2f36bb08c5146c6777031d507b2b6322 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Fri, 10 May 2013 00:14:55 -0500 Subject: [PATCH 34/42] Add release notes Fixes #471 --- release-notes.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 release-notes.md diff --git a/release-notes.md b/release-notes.md new file mode 100644 index 000000000..f55580f2e --- /dev/null +++ b/release-notes.md @@ -0,0 +1,49 @@ +# Release Notes + +## Development + +- #471 - Create release notes (These!) +- #458 - Fix `./foo` syntax (@jpfiset) +- #460 - Allow `:` in unescaped identifers (@jpfiset) +- #456 - Allow escaping of `\\` +- #211 - Fix exception in `escapeExpression` +- #375 - Escape unicode newlines +- #461 - Do not fail when compiling `""` +- #302 - Fix sanity check in knownHelpersOnly mode +- #369 - Allow registration of multiple helpers and partial by passing definition object +- Handle empty context in `with` (@thejohnfreeman) +- Support custom template extensions in CLI (@matteoagosti) +- Fix Rhino support (@broady) +- Include contexts in string mode (@leshill) +- Return precompiled scripts when compiling to AMD (@JamesMaroney) +- Docs updates (@iangreenleaf, @gilesbowkett, @utkarsh2012) +- Fix `toString` handling under IE and browserify (@tommydudebreaux) +- Add program metadata + +[Commits](https://github.com/wycats/handlebars.js/compare/v1.0.10...master) + +## v1.0.10 - Node - Feb 27 2013 + +- #428 - Fix incorrect rendering of nested programs +- Fix exception message (@tricknotes) +- Added negative number literal support +- Concert library to single IIFE +- Add handlebars-source gemspec (@machty) + +[Commits](https://github.com/wycats/handlebars.js/compare/v1.0.9...v1.0.10) + +## v1.0.9 - Node - Feb 15 2013 + +- Added `Handlebars.create` API in node module for sandboxed instances (@tommydudebreaux) + +[Commits](https://github.com/wycats/handlebars.js/compare/1.0.0-rc.3...v1.0.9) + +## 1.0.0-rc3 - Browser - Feb 14 2013 + +- Prevent use of `this` or `..` in illogical place (@leshill) +- Allow AST passing for `parse`/`compile`/`precompile` (@machty) +- Optimize generated output by inlining statements where possible +- Check compiler version when evaluating templates +- Package browser dist in npm package + +[Commits](https://github.com/wycats/handlebars.js/compare/v1.0.8...1.0.0-rc.3) From d355d1f6aa437c1cbaac14d55f53d48adde01e4e Mon Sep 17 00:00:00 2001 From: Kevin Decker Date: Fri, 10 May 2013 00:35:05 -0500 Subject: [PATCH 35/42] Fix links in release notes --- release-notes.md | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/release-notes.md b/release-notes.md index f55580f2e..828ab9c06 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,46 +2,47 @@ ## Development -- #471 - Create release notes (These!) -- #458 - Fix `./foo` syntax (@jpfiset) -- #460 - Allow `:` in unescaped identifers (@jpfiset) -- #456 - Allow escaping of `\\` -- #211 - Fix exception in `escapeExpression` -- #375 - Escape unicode newlines -- #461 - Do not fail when compiling `""` -- #302 - Fix sanity check in knownHelpersOnly mode -- #369 - Allow registration of multiple helpers and partial by passing definition object -- Handle empty context in `with` (@thejohnfreeman) -- Support custom template extensions in CLI (@matteoagosti) -- Fix Rhino support (@broady) -- Include contexts in string mode (@leshill) -- Return precompiled scripts when compiling to AMD (@JamesMaroney) -- Docs updates (@iangreenleaf, @gilesbowkett, @utkarsh2012) -- Fix `toString` handling under IE and browserify (@tommydudebreaux) +- [#458](https://github.com/wycats/handlebars.js/issues/458) - Fix `./foo` syntax ([@jpfiset](https://github.com/jpfiset)) +- [#460](https://github.com/wycats/handlebars.js/issues/460) - Allow `:` in unescaped identifers ([@jpfiset](https://github.com/jpfiset)) +- [#471](https://github.com/wycats/handlebars.js/issues/471) - Create release notes (These!) +- [#456](https://github.com/wycats/handlebars.js/issues/456) - Allow escaping of `\\` +- [#211](https://github.com/wycats/handlebars.js/issues/211) - Fix exception in `escapeExpression` +- [#375](https://github.com/wycats/handlebars.js/issues/375) - Escape unicode newlines +- [#461](https://github.com/wycats/handlebars.js/issues/461) - Do not fail when compiling `""` +- [#302](https://github.com/wycats/handlebars.js/issues/302) - Fix sanity check in knownHelpersOnly mode +- [#369](https://github.com/wycats/handlebars.js/issues/369) - Allow registration of multiple helpers and partial by passing definition object +- Add bower package declaration ([@DevinClark](https://github.com/DevinClark)) +- Handle empty context in `with` ([@thejohnfreeman](https://github.com/thejohnfreeman)) +- Support custom template extensions in CLI ([@matteoagosti](https://github.com/matteoagosti)) +- Fix Rhino support ([@broady](https://github.com/broady)) +- Include contexts in string mode ([@leshill](https://github.com/leshill)) +- Return precompiled scripts when compiling to AMD ([@JamesMaroney](https://github.com/JamesMaroney)) +- Docs updates ([@iangreenleaf](https://github.com/iangreenleaf), [@gilesbowkett](https://github.com/gilesbowkett), [@utkarsh2012](https://github.com/utkarsh2012)) +- Fix `toString` handling under IE and browserify ([@tommydudebreaux](https://github.com/tommydudebreaux)) - Add program metadata [Commits](https://github.com/wycats/handlebars.js/compare/v1.0.10...master) ## v1.0.10 - Node - Feb 27 2013 -- #428 - Fix incorrect rendering of nested programs -- Fix exception message (@tricknotes) +- [#428](https://github.com/wycats/handlebars.js/issues/428) - Fix incorrect rendering of nested programs +- Fix exception message ([@tricknotes](https://github.com/tricknotes)) - Added negative number literal support - Concert library to single IIFE -- Add handlebars-source gemspec (@machty) +- Add handlebars-source gemspec ([@machty](https://github.com/machty)) [Commits](https://github.com/wycats/handlebars.js/compare/v1.0.9...v1.0.10) ## v1.0.9 - Node - Feb 15 2013 -- Added `Handlebars.create` API in node module for sandboxed instances (@tommydudebreaux) +- Added `Handlebars.create` API in node module for sandboxed instances ([@tommydudebreaux](https://github.com/tommydudebreaux)) [Commits](https://github.com/wycats/handlebars.js/compare/1.0.0-rc.3...v1.0.9) ## 1.0.0-rc3 - Browser - Feb 14 2013 -- Prevent use of `this` or `..` in illogical place (@leshill) -- Allow AST passing for `parse`/`compile`/`precompile` (@machty) +- Prevent use of `this` or `..` in illogical place ([@leshill](https://github.com/leshill)) +- Allow AST passing for `parse`/`compile`/`precompile` ([@machty](https://github.com/machty)) - Optimize generated output by inlining statements where possible - Check compiler version when evaluating templates - Package browser dist in npm package From 436973f4703d736b735fa74abeb7e479badf75ff Mon Sep 17 00:00:00 2001 From: kpdecker Date: Fri, 10 May 2013 01:00:39 -0500 Subject: [PATCH 36/42] Version update script --- Rakefile | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 6fe5d849e..ac935ddb2 100644 --- a/Rakefile +++ b/Rakefile @@ -90,8 +90,24 @@ task :runtime => [:compile] do |task| Rake::Task["dist/handlebars.runtime.js"].execute end +# Updates the various version numbers. +task :version => [] do |task| + # TODO : Pull from package.json when the version numbers are synced + version = File.read("lib/handlebars/base.js").match(/Handlebars.VERSION = "(.*)";/)[1] + + content = File.read("bower.json") + File.open("bower.json", "w") do |file| + file.puts content.gsub(/"version":.*/, "\"version\": \"#{version}\",") + end + + content = File.read("handlebars.js.nuspec") + File.open("handlebars.js.nuspec", "w") do |file| + file.puts content.gsub(/.*<\/version>/, "#{version}") + end +end + desc "build the build and runtime version of handlebars" -task :release => [:build, :runtime] +task :release => [:version, :build, :runtime] directory "vendor" From fa6cec26bfb03f40f38d2352b7d16d634152b8cf Mon Sep 17 00:00:00 2001 From: kpdecker Date: Fri, 10 May 2013 01:02:13 -0500 Subject: [PATCH 37/42] Update client packager versions --- bower.json | 2 +- handlebars.js.nuspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 320a12b56..7aa992206 100644 --- a/bower.json +++ b/bower.json @@ -6,4 +6,4 @@ "node_modules", "components" ] -} \ No newline at end of file +} diff --git a/handlebars.js.nuspec b/handlebars.js.nuspec index e0d00edfd..5c7bf72a8 100644 --- a/handlebars.js.nuspec +++ b/handlebars.js.nuspec @@ -2,7 +2,7 @@ handlebars.js - 1.0.10 + 1.0.0-rc.3 handlebars.js Authors https://github.com/wycats/handlebars.js/blob/master/LICENSE https://github.com/wycats/handlebars.js/ From 8b65fa771e3f2b1126f4988397cc651d98adbb67 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Fri, 10 May 2013 01:24:11 -0500 Subject: [PATCH 38/42] Update release notes --- release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/release-notes.md b/release-notes.md index 828ab9c06..69c7ea1b2 100644 --- a/release-notes.md +++ b/release-notes.md @@ -12,6 +12,7 @@ - [#302](https://github.com/wycats/handlebars.js/issues/302) - Fix sanity check in knownHelpersOnly mode - [#369](https://github.com/wycats/handlebars.js/issues/369) - Allow registration of multiple helpers and partial by passing definition object - Add bower package declaration ([@DevinClark](https://github.com/DevinClark)) +- Add NuSpec package declaration ([@MikeMayer](https://github.com/MikeMayer)) - Handle empty context in `with` ([@thejohnfreeman](https://github.com/thejohnfreeman)) - Support custom template extensions in CLI ([@matteoagosti](https://github.com/matteoagosti)) - Fix Rhino support ([@broady](https://github.com/broady)) From 85dd39427b6bbfc9b9bd9bdbd93e36710327d6ad Mon Sep 17 00:00:00 2001 From: kpdecker Date: Fri, 10 May 2013 01:35:25 -0500 Subject: [PATCH 39/42] Add regex escapes --- dist/handlebars.js | 2 +- src/handlebars.l | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/handlebars.js b/dist/handlebars.js index 963e72c27..94bd151b4 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -644,7 +644,7 @@ case 33: return 5; break; } }; -lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[}/ ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$:-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-\/]+)/,/^(?:$)/]; +lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[}/ ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$:\-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$\-\/]+)/,/^(?:$)/]; lexer.conditions = {"mu":{"rules":[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,33],"inclusive":false},"emu":{"rules":[3],"inclusive":false},"com":{"rules":[4],"inclusive":false},"par":{"rules":[31,32],"inclusive":false},"INITIAL":{"rules":[0,1,2,33],"inclusive":true}}; return lexer;})() parser.lexer = lexer; diff --git a/src/handlebars.l b/src/handlebars.l index 9af78ba34..8a17a4e28 100644 --- a/src/handlebars.l +++ b/src/handlebars.l @@ -44,11 +44,11 @@ "true"/[}\s] { return 'BOOLEAN'; } "false"/[}\s] { return 'BOOLEAN'; } \-?[0-9]+/[}\s] { return 'INTEGER'; } -[a-zA-Z0-9_$:-]+/[=}\s\/.] { return 'ID'; } +[a-zA-Z0-9_$:\-]+/[=}\s\/.] { return 'ID'; } '['[^\]]*']' { yytext = yytext.substr(1, yyleng-2); return 'ID'; } . { return 'INVALID'; } \s+ { /*ignore whitespace*/ } -[a-zA-Z0-9_$-\/]+ { this.popState(); return 'PARTIAL_NAME'; } +[a-zA-Z0-9_$\-\/]+ { this.popState(); return 'PARTIAL_NAME'; } <> { return 'EOF'; } From ddc4d318619251b5481151f76514432ced0cccae Mon Sep 17 00:00:00 2001 From: kpdecker Date: Mon, 13 May 2013 23:07:29 -0500 Subject: [PATCH 40/42] Rev to rc4 --- bower.json | 2 +- dist/handlebars.js | 2 +- dist/handlebars.runtime.js | 2 +- handlebars.js.nuspec | 2 +- lib/handlebars/base.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bower.json b/bower.json index 7aa992206..a5eb00b98 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "handlebars.js", - "version": "1.0.0-rc.3", + "version": "1.0.0-rc.4", "main": "dist/handlebars.js", "ignore": [ "node_modules", diff --git a/dist/handlebars.js b/dist/handlebars.js index 94bd151b4..96d86ea81 100644 --- a/dist/handlebars.js +++ b/dist/handlebars.js @@ -29,7 +29,7 @@ var Handlebars = {}; ; // lib/handlebars/base.js -Handlebars.VERSION = "1.0.0-rc.3"; +Handlebars.VERSION = "1.0.0-rc.4"; Handlebars.COMPILER_REVISION = 3; Handlebars.REVISION_CHANGES = { diff --git a/dist/handlebars.runtime.js b/dist/handlebars.runtime.js index b6ba8a51f..7dd40f62e 100644 --- a/dist/handlebars.runtime.js +++ b/dist/handlebars.runtime.js @@ -29,7 +29,7 @@ var Handlebars = {}; ; // lib/handlebars/base.js -Handlebars.VERSION = "1.0.0-rc.3"; +Handlebars.VERSION = "1.0.0-rc.4"; Handlebars.COMPILER_REVISION = 3; Handlebars.REVISION_CHANGES = { diff --git a/handlebars.js.nuspec b/handlebars.js.nuspec index 5c7bf72a8..9a16cc09d 100644 --- a/handlebars.js.nuspec +++ b/handlebars.js.nuspec @@ -2,7 +2,7 @@ handlebars.js - 1.0.0-rc.3 + 1.0.0-rc.4 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 5e7ea0e71..9f4fdb6eb 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -6,7 +6,7 @@ var Handlebars = {}; // BEGIN(BROWSER) -Handlebars.VERSION = "1.0.0-rc.3"; +Handlebars.VERSION = "1.0.0-rc.4"; Handlebars.COMPILER_REVISION = 3; Handlebars.REVISION_CHANGES = { From 2ec5a97f4a355b71c8b1fb775cb51d01011b1821 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Mon, 13 May 2013 23:08:43 -0500 Subject: [PATCH 41/42] Update release notes --- release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/release-notes.md b/release-notes.md index 69c7ea1b2..fb409c686 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,6 +2,10 @@ ## Development +[Commits](https://github.com/wycats/handlebars.js/compare/v1.0.11...master) + +## v1.0.11 / 1.0.0-rc4 - May 13 2013 + - [#458](https://github.com/wycats/handlebars.js/issues/458) - Fix `./foo` syntax ([@jpfiset](https://github.com/jpfiset)) - [#460](https://github.com/wycats/handlebars.js/issues/460) - Allow `:` in unescaped identifers ([@jpfiset](https://github.com/jpfiset)) - [#471](https://github.com/wycats/handlebars.js/issues/471) - Create release notes (These!) From 4cf0410b7cc3e06f09b98bbc42a3d2df8e561eba Mon Sep 17 00:00:00 2001 From: kpdecker Date: Mon, 13 May 2013 23:09:21 -0500 Subject: [PATCH 42/42] 1.0.11 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7dda35743..ab3f6831e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "handlebars", "description": "Extension of the Mustache logicless template language", - "version": "1.0.10", + "version": "1.0.11", "homepage": "http://www.handlebarsjs.com/", "keywords": [ "handlebars mustache template html"