fix: preserve trailing empty suffix in ɵɵtextInterpolateN calls#163
fix: preserve trailing empty suffix in ɵɵtextInterpolateN calls#163BenjaminDobler wants to merge 2 commits intovoidzero-dev:mainfrom
Conversation
ɵɵtextInterpolate1/2/...N always require all positional string args including the trailing suffix. When the suffix was an empty string, it was incorrectly dropped, causing `undefined` to be concatenated at runtime (e.g. `#1undefined` instead of `voidzero-dev#1`). Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
Closing this PR — after deeper investigation, the root cause analysis in the bug report is incorrect. Findings:
The reported |
Summary
ɵɵtextInterpolateNfunctions in the Angular runtime always require all positional string arguments. The signature follows the pattern:Internally these delegate to
interpolationN(lView, prefix, v0, ..., suffix)which concatenates all arguments:When
suffixis omitted in JavaScript, it becomesundefined, and string concatenation produces"undefined"in the output — e.g.#1undefinedinstead of#1.Root cause
In
reify_interpolation, the trailing string argument is only emitted when it is non-empty or whenhas_extra_argsistrue. TheInterpolateTextcall site passedhas_extra_args: false, causing the trailing""to be dropped for templates like#{{ idx }}where:strings = ["#", ""]— the prefix is"#", the suffix is""expressions = [idx]The empty suffix
""was silently dropped, producingɵɵtextInterpolate1("Remove #", idx)(2 args) instead of the correctɵɵtextInterpolate1("Remove #", idx, "")(3 args).The plain
{{ expr }}case (no surrounding text) is unaffected — it takes an early-return path that emitsɵɵtextInterpolate(v0)which only takes a single argument.The Angular compiler always emits the trailing suffix
The official Angular compiler (
@angular/compiler) always includes all string segments intextInterpolateNcalls, including trailing empty strings. For example,{{ first }} and {{ second }}produces:This fix aligns the OXC compiler output with the Angular compiler.
Fix
Pass
has_extra_args: truefor theInterpolateTextcase, ensuring the trailing empty string is always preserved. This is safe because:{{ expr }}case takes an early-return branch before the trailing-string logic, sotruevsfalsemakes no difference there""does not break positional argument alignmentReproduction
Any template with a static prefix before an interpolation in a text node:
Renders
#1undefinedinstead of#1.The existing test
for_listener_with_indexalso encodes this bug in its snapshot:Test plan
#{{ idx }}no longer appendsundefined🤖 Generated with Claude Code