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
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.
  • Loading branch information
ayazhafiz committed Oct 15, 2019
1 parent ad72c90 commit 9e2b784
Show file tree
Hide file tree
Showing 3 changed files with 17 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
7 changes: 7 additions & 0 deletions packages/compiler/test/render3/r3_ast_absolute_span_spec.ts
Expand Up @@ -44,6 +44,13 @@ 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', () => {
debugger;
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 9e2b784

Please sign in to comment.