fix(compiler): record correct end of expression (#34690)
This commit fixes a bug with the expression parser wherein the end index of an expression node was recorded as the start index of the next token, not the end index of the current token. Closes #33477 Closes https://github.com/angular/vscode-ng-language-service/issues/433 PR Close #34690
This commit is contained in:
@ -312,7 +312,14 @@ export class _ParseAST {
|
||||
*/
|
||||
get currentAbsoluteOffset(): number { return this.absoluteOffset + this.inputIndex; }
|
||||
|
||||
span(start: number) { return new ParseSpan(start, this.inputIndex); }
|
||||
span(start: number) {
|
||||
// `end` is either the
|
||||
// - end index of the current token
|
||||
// - start of the first token (this can happen e.g. when creating an implicit receiver)
|
||||
const curToken = this.peek(-1);
|
||||
const end = this.index > 0 ? curToken.end + this.offset : this.inputIndex;
|
||||
return new ParseSpan(start, end);
|
||||
}
|
||||
|
||||
sourceSpan(start: number): AbsoluteSourceSpan {
|
||||
const serial = `${start}@${this.inputIndex}`;
|
||||
@ -740,7 +747,6 @@ export class _ParseAST {
|
||||
const value = this.parseConditional();
|
||||
return new PropertyWrite(this.span(start), this.sourceSpan(start), receiver, id, value);
|
||||
} else {
|
||||
const span = this.span(start);
|
||||
return new PropertyRead(this.span(start), this.sourceSpan(start), receiver, id);
|
||||
}
|
||||
}
|
||||
@ -887,11 +893,7 @@ export class _ParseAST {
|
||||
return null;
|
||||
}
|
||||
const ast = this.parsePipe(); // example: "condition | async"
|
||||
const {start} = ast.span;
|
||||
// Getting the end of the last token removes trailing whitespace.
|
||||
// If ast has the correct end span then no need to peek at last token.
|
||||
// TODO(ayazhafiz): Remove this in https://github.com/angular/angular/pull/34690
|
||||
const {end} = this.peek(-1);
|
||||
const {start, end} = ast.span;
|
||||
const value = this.input.substring(start, end);
|
||||
return new ASTWithSource(ast, value, this.location, this.absoluteOffset + start, this.errors);
|
||||
}
|
||||
|
@ -516,7 +516,7 @@ describe('parser', () => {
|
||||
const bindings = parseTemplateBindings(attr);
|
||||
expect(humanizeSpans(bindings, attr)).toEqual([
|
||||
// source span, key span, value span
|
||||
['ngIf="cond | pipe ', 'ngIf', 'cond | pipe '],
|
||||
['ngIf="cond | pipe ', 'ngIf', 'cond | pipe'],
|
||||
['ngIf="cond | pipe as foo, ', 'foo', 'ngIf'],
|
||||
['let x; ', 'x', null],
|
||||
['ngIf as y', 'y', 'ngIf'],
|
||||
@ -531,7 +531,7 @@ describe('parser', () => {
|
||||
// source span, key span, value span
|
||||
['ngFor="', 'ngFor', null],
|
||||
['let item; ', 'item', null],
|
||||
['of items | slice:0:1 ', 'of', 'items | slice:0:1 '],
|
||||
['of items | slice:0:1 ', 'of', 'items | slice:0:1'],
|
||||
['of items | slice:0:1 as collection, ', 'collection', 'of'],
|
||||
['trackBy: func; ', 'trackBy', 'func'],
|
||||
['index as i', 'i', 'index'],
|
||||
@ -545,7 +545,7 @@ describe('parser', () => {
|
||||
// source span, key span, value span
|
||||
['ngFor="', 'ngFor', null],
|
||||
['let item, ', 'item', null],
|
||||
['of: [1,2,3] | pipe ', 'of', '[1,2,3] | pipe '],
|
||||
['of: [1,2,3] | pipe ', 'of', '[1,2,3] | pipe'],
|
||||
['of: [1,2,3] | pipe as items; ', 'items', 'of'],
|
||||
['let i=index, ', 'i', 'index'],
|
||||
['count as len, ', 'len', 'count'],
|
||||
|
@ -60,9 +60,7 @@ describe('expression AST absolute source spans', () => {
|
||||
it('should provide absolute offsets of expressions in a binary expression', () => {
|
||||
expect(humanizeExpressionSource(parse('<div>{{1 + 2}}<div>').nodes))
|
||||
.toEqual(jasmine.arrayContaining([
|
||||
// TODO(ayazhafiz): The expression parser includes an extra whitespace on a expressions
|
||||
// with trailing whitespace in a binary expression. Look into fixing this.
|
||||
['1', new AbsoluteSourceSpan(7, 9)],
|
||||
['1', new AbsoluteSourceSpan(7, 8)],
|
||||
['2', new AbsoluteSourceSpan(11, 12)],
|
||||
]));
|
||||
});
|
||||
@ -78,10 +76,8 @@ describe('expression AST absolute source spans', () => {
|
||||
it('should provide absolute offsets of expressions in a conditional', () => {
|
||||
expect(humanizeExpressionSource(parse('<div>{{bool ? 1 : 0}}<div>').nodes))
|
||||
.toEqual(jasmine.arrayContaining([
|
||||
// TODO(ayazhafiz): The expression parser includes an extra whitespace on a expressions
|
||||
// with trailing whitespace in a conditional expression. Look into fixing this.
|
||||
['bool', new AbsoluteSourceSpan(7, 12)],
|
||||
['1', new AbsoluteSourceSpan(14, 16)],
|
||||
['bool', new AbsoluteSourceSpan(7, 11)],
|
||||
['1', new AbsoluteSourceSpan(14, 15)],
|
||||
['0', new AbsoluteSourceSpan(18, 19)],
|
||||
]));
|
||||
});
|
||||
@ -133,9 +129,7 @@ describe('expression AST absolute source spans', () => {
|
||||
it('should provide absolute offsets of expressions in an interpolation', () => {
|
||||
expect(humanizeExpressionSource(parse('<div>{{1 + 2}}<div>').nodes))
|
||||
.toEqual(jasmine.arrayContaining([
|
||||
// TODO(ayazhafiz): The expression parser includes an extra whitespace on a expressions
|
||||
// with trailing whitespace in a conditional expression. Look into fixing this.
|
||||
['1', new AbsoluteSourceSpan(7, 9)],
|
||||
['1', new AbsoluteSourceSpan(7, 8)],
|
||||
['2', new AbsoluteSourceSpan(11, 12)],
|
||||
]));
|
||||
});
|
||||
@ -197,9 +191,7 @@ describe('expression AST absolute source spans', () => {
|
||||
describe('literal map', () => {
|
||||
it('should provide absolute offsets of a literal map', () => {
|
||||
expect(humanizeExpressionSource(parse('<div>{{ {a: 0} }}<div>').nodes)).toContain([
|
||||
// TODO(ayazhafiz): The expression parser includes an extra whitespace on a expressions
|
||||
// with trailing whitespace in a literal map. Look into fixing this.
|
||||
'{a: 0}', new AbsoluteSourceSpan(8, 15)
|
||||
'{a: 0}', new AbsoluteSourceSpan(8, 14)
|
||||
]);
|
||||
});
|
||||
|
||||
@ -248,9 +240,7 @@ describe('expression AST absolute source spans', () => {
|
||||
|
||||
it('should provide absolute offsets expressions in a pipe', () => {
|
||||
expect(humanizeExpressionSource(parse('<div>{{prop | pipe}}<div>').nodes)).toContain([
|
||||
// TODO(ayazhafiz): The expression parser includes an extra whitespace on a expressions
|
||||
// with trailing whitespace in a pipe. Look into fixing this.
|
||||
'prop', new AbsoluteSourceSpan(7, 12)
|
||||
'prop', new AbsoluteSourceSpan(7, 11)
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -94,9 +94,7 @@ describe('expression AST absolute source spans', () => {
|
||||
it('should provide absolute offsets of expressions in a binary expression', () => {
|
||||
expect(humanizeExpressionSource(parse('<div>{{1 + 2}}<div>')))
|
||||
.toEqual(jasmine.arrayContaining([
|
||||
// TODO(ayazhafiz): The expression parser includes an extra whitespace on a expressions
|
||||
// with trailing whitespace in a binary expression. Look into fixing this.
|
||||
['1', new AbsoluteSourceSpan(7, 9)],
|
||||
['1', new AbsoluteSourceSpan(7, 8)],
|
||||
['2', new AbsoluteSourceSpan(11, 12)],
|
||||
]));
|
||||
});
|
||||
@ -112,10 +110,8 @@ describe('expression AST absolute source spans', () => {
|
||||
it('should provide absolute offsets of expressions in a conditional', () => {
|
||||
expect(humanizeExpressionSource(parse('<div>{{bool ? 1 : 0}}<div>')))
|
||||
.toEqual(jasmine.arrayContaining([
|
||||
// TODO(ayazhafiz): The expression parser includes an extra whitespace on a expressions
|
||||
// with trailing whitespace in a conditional expression. Look into fixing this.
|
||||
['bool', new AbsoluteSourceSpan(7, 12)],
|
||||
['1', new AbsoluteSourceSpan(14, 16)],
|
||||
['bool', new AbsoluteSourceSpan(7, 11)],
|
||||
['1', new AbsoluteSourceSpan(14, 15)],
|
||||
['0', new AbsoluteSourceSpan(18, 19)],
|
||||
]));
|
||||
});
|
||||
@ -167,9 +163,7 @@ describe('expression AST absolute source spans', () => {
|
||||
it('should provide absolute offsets of expressions in an interpolation', () => {
|
||||
expect(humanizeExpressionSource(parse('<div>{{1 + 2}}<div>')))
|
||||
.toEqual(jasmine.arrayContaining([
|
||||
// TODO(ayazhafiz): The expression parser includes an extra whitespace on a expressions
|
||||
// with trailing whitespace in a conditional expression. Look into fixing this.
|
||||
['1', new AbsoluteSourceSpan(7, 9)],
|
||||
['1', new AbsoluteSourceSpan(7, 8)],
|
||||
['2', new AbsoluteSourceSpan(11, 12)],
|
||||
]));
|
||||
});
|
||||
@ -231,9 +225,7 @@ describe('expression AST absolute source spans', () => {
|
||||
describe('literal map', () => {
|
||||
it('should provide absolute offsets of a literal map', () => {
|
||||
expect(humanizeExpressionSource(parse('<div>{{ {a: 0} }}<div>'))).toContain([
|
||||
// TODO(ayazhafiz): The expression parser includes an extra whitespace on a expressions
|
||||
// with trailing whitespace in a literal map. Look into fixing this.
|
||||
'{a: 0}', new AbsoluteSourceSpan(8, 15)
|
||||
'{a: 0}', new AbsoluteSourceSpan(8, 14)
|
||||
]);
|
||||
});
|
||||
|
||||
@ -287,11 +279,7 @@ describe('expression AST absolute source spans', () => {
|
||||
|
||||
it('should provide absolute offsets expressions in a pipe', () => {
|
||||
expect(humanizeExpressionSource(parse('<div>{{prop | test}}<div>', [], [testPipe])))
|
||||
.toContain([
|
||||
// TODO(ayazhafiz): The expression parser includes an extra whitespace on a expressions
|
||||
// with trailing whitespace in a pipe. Look into fixing this.
|
||||
'prop', new AbsoluteSourceSpan(7, 12)
|
||||
]);
|
||||
.toContain(['prop', new AbsoluteSourceSpan(7, 11)]);
|
||||
});
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user