Skip to content

Commit

Permalink
fix(compiler): absolute source span for template attribute expressions (
Browse files Browse the repository at this point in the history
angular#33189)

Prior to this commit, the absolute spans (relative to template source
file rather than the start of an expression) of expressions in a
template attribute like `*ngIf` were generated incorrectly, equating to
the relative spans.
This fixes the bug by passing an `absoluteOffset` parameter when parsing
template bindings.

Through some levels of indirection, this is required for the Language
Service to support text replacement in
angular#33091.

PR Close angular#33189
  • Loading branch information
ayazhafiz authored and AndrusGerman committed Oct 22, 2019
1 parent d33798b commit 893a436
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 6 deletions.
11 changes: 6 additions & 5 deletions packages/compiler/src/template_parser/binding_parser.ts
Expand Up @@ -118,7 +118,7 @@ export class BindingParser {
tplKey: string, tplValue: string, sourceSpan: ParseSourceSpan, absoluteOffset: number,
targetMatchableAttrs: string[][], targetProps: ParsedProperty[],
targetVars: ParsedVariable[]) {
const bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan);
const bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteOffset);

for (let i = 0; i < bindings.length; i++) {
const binding = bindings[i];
Expand All @@ -137,13 +137,14 @@ export class BindingParser {
}
}

private _parseTemplateBindings(tplKey: string, tplValue: string, sourceSpan: ParseSourceSpan):
TemplateBinding[] {
private _parseTemplateBindings(
tplKey: string, tplValue: string, sourceSpan: ParseSourceSpan,
absoluteOffset: number): TemplateBinding[] {
const sourceInfo = sourceSpan.start.toString();

try {
const bindingsResult = this._exprParser.parseTemplateBindings(
tplKey, tplValue, sourceInfo, sourceSpan.start.offset);
const bindingsResult =
this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceInfo, absoluteOffset);
this._reportExpressionParserErrors(bindingsResult.errors, sourceSpan);
bindingsResult.templateBindings.forEach((binding) => {
if (binding.expression) {
Expand Down
6 changes: 6 additions & 0 deletions packages/compiler/test/render3/r3_ast_absolute_span_spec.ts
Expand Up @@ -44,6 +44,12 @@ describe('expression AST absolute source spans', () => {
.toContain(['condition ? true : false', new AbsoluteSourceSpan(22, 46)]);
});

it('should provide absolute offsets of an expression in a template attribute', () => {
expect(humanizeExpressionSource(parse('<div *ngIf="value | async"></div>').nodes)).toContain([
'(value | async)', new AbsoluteSourceSpan(12, 25)
]);
});

describe('binary expression', () => {
it('should provide absolute offsets of a binary expression', () => {
expect(humanizeExpressionSource(parse('<div>{{1 + 2}}<div>').nodes)).toContain([
Expand Down
5 changes: 4 additions & 1 deletion packages/compiler/test/render3/util/expression.ts
Expand Up @@ -102,7 +102,10 @@ class ExpressionSourceHumanizer extends e.RecursiveAstVisitor implements t.Visit
super.visitQuote(ast, null);
}

visitTemplate(ast: t.Template) { t.visitAll(this, ast.children); }
visitTemplate(ast: t.Template) {
t.visitAll(this, ast.children);
t.visitAll(this, ast.templateAttrs);
}
visitElement(ast: t.Element) {
t.visitAll(this, ast.children);
t.visitAll(this, ast.inputs);
Expand Down

0 comments on commit 893a436

Please sign in to comment.