Fixes
Both regressions below were introduced on 2026-06-20 and shipped in 2.4.0 (released 2026-08-06). Neither was an intentional public API change — this release restores prior correct behavior.
- Static template text no longer has its line endings silently rewritten. A fix for internal indentation handling started normalizing every
\r\n/\rin static template text to\n, so a literal\r\na caller wrote into a template string (e.g. between{{#each}}iterations) was silently turned into\n. Static text now round-trips verbatim, matching this library's long-standing behavior and handlebars.js. (#663, fixes #661) - Subexpression results are plain strings again, not an internal wrapper type. A fix for double-encoding across subexpression boundaries (#543) wrapped every writer-based helper's captured output in an
internal sealed class SafeStringwhen used as a subexpression argument. Only a few internal call sites knew how to unwrap it — any other consumer, including reflection-based/typed helper binders in third-party packages (e.g.Handlebars.Net.Helpers), received an opaque type it could neither cast tostringnor unwrap, throwingInvalidCastException. The double-encoding fix is preserved, but the signal is now carried by an invisible reference-keyed marker instead of a boxing type, so the value is a genuineSystem.Stringeverywhere except the one place that needs to know. (#664, fixes #660)
Compatibility notes
- No API surface changes. Both fixes are behavior reverts to what 2.3.0 and earlier already did; anything that worked before 2.4.0 works the same way again.
- If your code adapted to either regression (e.g. expected
\n-only output regardless of source line endings, or handled aSafeString-typed subexpression argument), that adaptation is no longer necessary but should remain harmless.
Contributors
Full Changelog: 2.4.0...2.4.1