angular / angular

Deliver web apps with confidence 🚀
https://angular.dev
MIT License
94.71k stars 24.68k forks source link

Template parser produces inaccurate source spans when `preserveWhitespaces` is false or omitted #55633

Closed not-my-profile closed 2 weeks ago

not-my-profile commented 2 weeks ago

Which @angular/* package(s) are the source of the bug?

compiler

Description

import { Interpolation, TmplAstBoundText, parseTemplate } from "@angular/compiler";

const html = `{{'foo' | bar}}  {{'foo' | bar}}`;
const template = parseTemplate(html, "fake url");

for (const node of template.nodes) {
  if (node instanceof TmplAstBoundText) {
    if (node.value.ast instanceof Interpolation) {
      for (const expr of node.value.ast.expressions) {
        console.log(html.slice(expr.sourceSpan.start, expr.sourceSpan.end));
      }
    }
  }
}

Prints the following:

'foo' | bar
{'foo' | ba

As you can see the sourceSpan of the second BindingPipe is incorrect. Inserting more spaces between the two interpolations makes the spans even more off.

Please provide the environment you discovered this bug in (run ng version)

Observed with @angular/compiler 17.3.7.

JoostK commented 2 weeks ago

This is a well-known problem of Angular's parser infrastructure. You need to enable preserveWhitespaces for proper source spans.

const template = parseTemplate(html, 'fake url', {
  preserveWhitespaces: true,
});
JoostK commented 2 weeks ago

Ideally this wouldn't be the case, as we currently have to work around this problem in the compiler as well:

https://github.com/angular/angular/blob/a0ec2d8915ca408d1bb415a0da0180c34c4a9f51/packages/compiler-cli/src/ngtsc/annotations/component/src/resources.ts#L274-L287

alxhub commented 2 weeks ago

Closing as the Angular compiler isn't really public API and there's a workaround for anyone using the private API to parse templates.