fix(compiler-cli): preserve user line endings in diagnostic template parse (#40597)

Normally the template parsing operation normalizes all template line endings
to '\n' only. This normalization operation causes source mapping errors when
the original template uses '\r\n' line endings.

The compiler already parses templates again to create a "diagnostic"
template AST with accurate source maps, to avoid other parsing issues that
affect source map accuracy. This commit configures this diagnostic parse to
also preserve line endings.

PR Close #40597
This commit is contained in:
Alex Rickabaugh 2021-01-27 11:25:38 -08:00 committed by Misko Hevery
parent 4b3106ed8a
commit bd0d19141b
3 changed files with 26 additions and 2 deletions

View File

@ -869,12 +869,14 @@ export class ComponentDecoratorHandler implements
// Unfortunately, the primary parse of the template above may not contain accurate source map
// information. If used directly, it would result in incorrect code locations in template
// errors, etc. There are two main problems:
// errors, etc. There are three main problems:
//
// 1. `preserveWhitespaces: false` annihilates the correctness of template source mapping, as
// the whitespace transformation changes the contents of HTML text nodes before they're
// parsed into Angular expressions.
// 2. By default, the template parser strips leading trivia characters (like spaces, tabs, and
// 2. `preserveLineEndings: false` causes growing misalignments in templates that use '\r\n'
// line endings, by normalizing them to '\n'.
// 3. By default, the template parser strips leading trivia characters (like spaces, tabs, and
// newlines). This also destroys source mapping information.
//
// In order to guarantee the correctness of diagnostics, templates are parsed a second time
@ -885,6 +887,7 @@ export class ComponentDecoratorHandler implements
const {nodes: diagNodes} = parseTemplate(templateStr, template.sourceMapUrl, {
preserveWhitespaces: true,
preserveLineEndings: true,
interpolationConfig: template.interpolationConfig,
range: templateRange ?? undefined,
escapedString,

View File

@ -110,6 +110,23 @@ export declare class AnimationEvent {
env.driveMain();
});
it('should have accurate diagnostics in a template using crlf line endings', () => {
env.write('test.ts', `
import {Component} from '@angular/core';
@Component({
selector: 'test',
templateUrl: './test.html',
})
class TestCmp {}
`);
env.write('test.html', '<span>\r\n{{does_not_exist}}\r\n</span>');
const diags = env.driveDiagnostics();
expect(diags.length).toBe(1);
expect(getSourceCodeForDiagnostic(diags[0])).toBe('does_not_exist');
});
it('should check regular attributes that are directive inputs', () => {
env.tsconfig(
{fullTemplateTypeCheck: true, strictInputTypes: true, strictAttributeTypes: true});

View File

@ -2003,6 +2003,10 @@ export interface ParseTemplateOptions {
* Include whitespace nodes in the parsed output.
*/
preserveWhitespaces?: boolean;
/**
* Preserve original line endings instead of normalizing '\r\n' endings to '\n'.
*/
preserveLineEndings?: boolean;
/**
* How to parse interpolation markers.
*/