From bce7ce45cbb6e420891750171d3f6dcc665a1561 Mon Sep 17 00:00:00 2001 From: ShivamChaudhary Date: Fri, 20 Feb 2026 14:24:55 +0530 Subject: [PATCH 1/2] fix: use parsed integer num instead of rawNum in repeat helper loop --- src/helpers/repeat.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/repeat.ts b/src/helpers/repeat.ts index 881c51a..43ff933 100644 --- a/src/helpers/repeat.ts +++ b/src/helpers/repeat.ts @@ -9,7 +9,7 @@ export const repeatHelper: HelperConstructorBlock = (ctx) => { } let ret = ""; - for (let i = 0; i < rawNum; i++) { + for (let i = 0; i < num; i++) { ret += options.fn({ ...this, "repeat_index": i }); } return ret; From bd73f93841afa91dc55a928b6e3f942b2a1295ac Mon Sep 17 00:00:00 2001 From: alondmnt Date: Wed, 16 Sep 2026 23:47:13 +1000 Subject: [PATCH 2/2] test: cover the repeat helper's parsed count Adds the regression test requested in review. Both cases fail against the unfixed helper and pass with it. parseInt and the loop's own coercion disagree on anything that is not a clean integer string: - "3abc": parseInt gives 3, Number gives NaN, so comparing against the raw string ran zero iterations and produced nothing at all - "3.7": parseInt gives 3, Number gives 3.7, so the raw comparison ran one iteration too many Note that "abc" cannot cover this, which was suggested earlier in the review thread. parseInt returns NaN for it, so the helper throws before reaching the loop and never exercises the difference. That path is already covered by the existing "should throw on non-numeric input". --- tests/helpers/helpers.spec.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/helpers/helpers.spec.ts b/tests/helpers/helpers.spec.ts index b43a36c..e1daca5 100644 --- a/tests/helpers/helpers.spec.ts +++ b/tests/helpers/helpers.spec.ts @@ -334,6 +334,21 @@ describe("Handlebars Helpers", () => { expect(template({ count: -1 })).toEqual(""); }); + // Regression test for #124. parseInt and the loop's own coercion + // disagree on trailing garbage: parseInt("3abc") is 3, but Number("3abc") + // is NaN, so comparing against the raw string silently produced nothing. + test("should use the parsed count when the input has trailing characters", () => { + const template = Handlebars.compile("{{#repeat count}}item{{/repeat}}"); + expect(template({ count: "3abc" })).toEqual("itemitemitem"); + }); + + // Same disagreement in the other direction: Number("3.7") is 3.7, so the + // raw comparison ran one iteration too many. + test("should use the parsed count when the input is fractional", () => { + const template = Handlebars.compile("{{#repeat count}}item{{/repeat}}"); + expect(template({ count: "3.7" })).toEqual("itemitemitem"); + }); + test("should repeat exactly once for count of 1", () => { const template = Handlebars.compile("{{#repeat 1}}only{{/repeat}}"); expect(template({})).toEqual("only");