From 13a7a679910d2adbfe7f6fad61ce8f98426b0378 Mon Sep 17 00:00:00 2001 From: Alexander Kireyev Date: Thu, 25 Jun 2026 06:40:45 +0700 Subject: [PATCH] Fix noEscape numeric values being added instead of concatenated (#2167) * Fix noEscape numeric values being added instead of concatenated In the inline output path, an unescaped mustache emitted the raw value (`value != null ? value : ""`) rather than a string. When two such appends were merged with ` + ` and both values were numbers, JavaScript performed numeric addition: `{{a}}{{b}}` with noEscape and a=1, b=2 produced "3" instead of "12". The same affected triple-stash `{{{a}}}`. Coerce non-null values to a String in the inline append, matching the escaped path and the documented contract of `append` ("Coerces value to a String"). * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Igor Savin Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- lib/handlebars/compiler/javascript-compiler.js | 5 ++++- spec/basic.js | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index 6e7a0c12c..ef3fa71a5 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -426,7 +426,10 @@ JavaScriptCompiler.prototype = { // Otherwise, the empty string is appended append: function () { if (this.isInline()) { - this.replaceStack((current) => [' != null ? ', current, ' : ""']); + // Coerce non-null values to a String so that adjacent buffer appends are + // concatenated rather than combined by the merge `+` (e.g. numeric values + // such as `{{a}}{{b}}` with `noEscape` must yield "12", not 3). + this.replaceStack((current) => [' != null ? "" + ', current, ' : ""']); this.pushSource(this.appendToBuffer(this.popStack())); } else { diff --git a/spec/basic.js b/spec/basic.js index f3d37e250..9809148d3 100644 --- a/spec/basic.js +++ b/spec/basic.js @@ -111,6 +111,22 @@ describe('basic context', function () { .toCompileTo('num: 0'); }); + it('does not add adjacent numeric values with noEscape or raw mustaches', function () { + expectTemplate('{{a}}{{b}}') + .withCompileOptions({ noEscape: true }) + .withInput({ a: 1, b: 2 }) + .toCompileTo('12'); + + expectTemplate('{{a}}{{b}}{{c}}') + .withCompileOptions({ noEscape: true }) + .withInput({ a: 1, b: 2, c: 3 }) + .toCompileTo('123'); + + expectTemplate('{{{a}}}{{{b}}}') + .withInput({ a: 1, b: 2 }) + .toCompileTo('12'); + }); + it('false', function () { /* eslint-disable no-new-wrappers */ expectTemplate('val1: {{val1}}, val2: {{val2}}')