From caafac2248d9dcdccf9f83e12e421f07371f07c4 Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Wed, 27 Jan 2021 11:25:38 -0800 Subject: [PATCH] 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 --- .../src/ngtsc/annotations/src/component.ts | 7 +++++-- .../test/ngtsc/template_typecheck_spec.ts | 17 +++++++++++++++++ packages/compiler/src/render3/view/template.ts | 4 ++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts index 9f1805088c8..5db7d33e45a 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts @@ -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, diff --git a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts index f63a075015c..fc060b60986 100644 --- a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts +++ b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts @@ -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', '\r\n{{does_not_exist}}\r\n'); + + 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}); diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index a1e77ada50b..e7d7618cc8a 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -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. */