refactor(compiler-cli): make template parsing errors into diagnostics (#38576)

Previously, the compiler was not able to display template parsing errors as
true `ts.Diagnostic`s that point inside the template. Instead, it would
throw an actual `Error`, and "crash" with a stack trace containing the
template errors.

Not only is this a poor user experience, but it causes the Language Service
to also crash as the user is editing a template (in actuality the LS has to
work around this bug).

With this commit, such parsing errors are converted to true template
diagnostics with appropriate span information to be displayed contextually
along with all other diagnostics. This majorly improves the user experience
and unblocks the Language Service from having to deal with the compiler
"crashing" to report errors.

PR Close #38576
This commit is contained in:
Alex Rickabaugh
2020-08-25 09:46:40 -04:00
committed by Andrew Scott
parent 1c2ccfed4d
commit 9bf32c4dcb
6 changed files with 84 additions and 10 deletions

View File

@ -7378,6 +7378,54 @@ export const Foo = Foo__PRE_R3__;
const diags = env.driveDiagnostics();
expect(diags.length).toBe(0);
});
describe('template parsing diagnostics', () => {
// These tests validate that errors which occur during template parsing are expressed as
// diagnostics instead of a compiler crash (which used to be the case). They only assert
// that the error is produced with an accurate span - the exact semantics of the errors are
// tested separately, via the parser tests.
it('should emit a diagnostic for a template parsing error', () => {
env.write('test.ts', `
import {Component} from '@angular/core';
@Component({
template: '<div></span>',
selector: 'test-cmp',
})
export class TestCmp {}
`);
const diags = env.driveDiagnostics();
expect(diags.length).toBe(1);
expect(getDiagnosticSourceCode(diags[0])).toBe('</span>');
});
it('should emit a diagnostic for an expression parsing error', () => {
env.write('test.ts', `
import {Component} from '@angular/core';
@Component({
template: '<cmp [input]="x ? y">',
selector: 'test-cmp',
})
export class TestCmp {}
`);
const diags = env.driveDiagnostics();
expect(diags.length).toBe(1);
expect(getDiagnosticSourceCode(diags[0])).toBe('x ? y');
});
it('should use a single character span for an unexpected EOF parsing error', () => {
env.write('test.ts', `
import {Component} from '@angular/core';
@Component({
template: '<cmp [input]="x>',
selector: 'test-cmp',
})
export class TestCmp {}
`);
const diags = env.driveDiagnostics();
expect(diags.length).toBe(1);
expect(getDiagnosticSourceCode(diags[0])).toBe('\'');
});
});
});
});