From bd0d19141b241173439cb7ed8b8578d4c0ee60a2 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 9f1805088c..5db7d33e45 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 f63a075015..fc060b6098 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 a1e77ada50..e7d7618cc8 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. */