fix(compiler): narrow the span reported for invalid pipes
fixes #13326 closes #13411
This commit is contained in:
parent
3a64ad895a
commit
2b90cd532f
|
@ -344,7 +344,7 @@ export class _ParseAST {
|
|||
while (this.optionalCharacter(chars.$COLON)) {
|
||||
args.push(this.parseExpression());
|
||||
}
|
||||
result = new BindingPipe(this.span(result.span.start - this.offset), result, name, args);
|
||||
result = new BindingPipe(this.span(result.span.start), result, name, args);
|
||||
} while (this.optionalOperator('|'));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import * as chars from './chars';
|
||||
import {isPresent} from './facade/lang';
|
||||
|
||||
export class ParseLocation {
|
||||
|
@ -15,6 +16,38 @@ export class ParseLocation {
|
|||
toString(): string {
|
||||
return isPresent(this.offset) ? `${this.file.url}@${this.line}:${this.col}` : this.file.url;
|
||||
}
|
||||
|
||||
moveBy(delta: number): ParseLocation {
|
||||
const source = this.file.content;
|
||||
const len = source.length;
|
||||
let offset = this.offset;
|
||||
let line = this.line;
|
||||
let col = this.col;
|
||||
while (offset > 0 && delta < 0) {
|
||||
offset--;
|
||||
delta++;
|
||||
const ch = source.charCodeAt(offset);
|
||||
if (ch == chars.$LF) {
|
||||
line--;
|
||||
const priorLine = source.substr(0, offset - 1).lastIndexOf(String.fromCharCode(chars.$LF));
|
||||
col = priorLine > 0 ? offset - priorLine : offset;
|
||||
} else {
|
||||
col--;
|
||||
}
|
||||
}
|
||||
while (offset < len && delta > 0) {
|
||||
const ch = source.charCodeAt(offset);
|
||||
offset++;
|
||||
delta--;
|
||||
if (ch == chars.$LF) {
|
||||
line++;
|
||||
col = 0;
|
||||
} else {
|
||||
col++;
|
||||
}
|
||||
}
|
||||
return new ParseLocation(this.file, offset, line, col);
|
||||
}
|
||||
}
|
||||
|
||||
export class ParseSourceFile {
|
||||
|
|
|
@ -377,9 +377,12 @@ export class BindingParser {
|
|||
if (isPresent(ast)) {
|
||||
const collector = new PipeCollector();
|
||||
ast.visit(collector);
|
||||
collector.pipes.forEach((pipeName) => {
|
||||
collector.pipes.forEach((ast, pipeName) => {
|
||||
if (!this.pipesByName.has(pipeName)) {
|
||||
this._reportError(`The pipe '${pipeName}' could not be found`, sourceSpan);
|
||||
this._reportError(
|
||||
`The pipe '${pipeName}' could not be found`,
|
||||
new ParseSourceSpan(
|
||||
sourceSpan.start.moveBy(ast.span.start), sourceSpan.start.moveBy(ast.span.end)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -402,9 +405,9 @@ export class BindingParser {
|
|||
}
|
||||
|
||||
export class PipeCollector extends RecursiveAstVisitor {
|
||||
pipes = new Set<string>();
|
||||
pipes = new Map<string, BindingPipe>();
|
||||
visitPipe(ast: BindingPipe, context: any): any {
|
||||
this.pipes.add(ast.name);
|
||||
this.pipes.set(ast.name, ast);
|
||||
ast.exp.visit(this);
|
||||
this.visitAll(ast.args, context);
|
||||
return null;
|
||||
|
|
|
@ -1839,7 +1839,7 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
|
||||
it('should report pipes as error that have not been defined as dependencies', () => {
|
||||
expect(() => parse('{{a | test}}', [])).toThrowError(`Template parse errors:
|
||||
The pipe 'test' could not be found ("[ERROR ->]{{a | test}}"): TestComp@0:0`);
|
||||
The pipe 'test' could not be found ("{{[ERROR ->]a | test}}"): TestComp@0:2`);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -151,6 +151,18 @@ describe('diagnostics', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// Issue #13326
|
||||
it('should report a narrow span for invalid pipes', () => {
|
||||
const code =
|
||||
` @Component({template: '<p> Using an invalid pipe {{data | dat}} </p>'}) export class MyComponent { data = 'some data'; }`;
|
||||
addCode(code, fileName => {
|
||||
const diagnostic =
|
||||
ngService.getDiagnostics(fileName).filter(d => d.message.indexOf('pipe') > 0)[0];
|
||||
expect(diagnostic).not.toBeUndefined();
|
||||
expect(diagnostic.span.end - diagnostic.span.start).toBeLessThan(11);
|
||||
});
|
||||
});
|
||||
|
||||
function addCode(code: string, cb: (fileName: string, content?: string) => void) {
|
||||
const fileName = '/app/app.component.ts';
|
||||
const originalContent = mockHost.getFileContent(fileName);
|
||||
|
|
Loading…
Reference in New Issue