From 3fada9ee7e670be8dfd59fe4a168c292830a6f2d Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Tue, 2 Nov 2021 10:23:59 +0000 Subject: [PATCH] fix(migrations): account for CRLF characters in template migrations (#44013) Previously, when parsing code for templates to migrate, CRLF characters were converted to just LF. This meant that the source-spans being used to overwrite the template strings in the original source code were out of sync with the positions identified in the parsed templates. This commit fixes this by parsing the raw text of the template taken from the source code instead of processed string contents. Fixes #44005 PR Close #44013 --- .../routerlink_empty_expr_migration_spec.ts | 27 ++++++++++++++++--- .../schematics/utils/ng_component_template.ts | 16 ++++++++--- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/packages/core/schematics/test/routerlink_empty_expr_migration_spec.ts b/packages/core/schematics/test/routerlink_empty_expr_migration_spec.ts index f4184bbf6d8..be2f78a3078 100644 --- a/packages/core/schematics/test/routerlink_empty_expr_migration_spec.ts +++ b/packages/core/schematics/test/routerlink_empty_expr_migration_spec.ts @@ -76,7 +76,7 @@ describe('routerlink emptyExpr assignment migration', () => { await runMigration(); expect(warnOutput.length).toBe(1); - expect(warnOutput[0]).toMatch(/^⮑ {3}index.ts@5:25/); + expect(warnOutput[0]).toMatch(/^⮑ {3}index\.ts@5:25/); const content = tree.readContent('/index.ts'); expect(content).toContain(`
`); @@ -101,7 +101,7 @@ describe('routerlink emptyExpr assignment migration', () => { await runMigration(); expect(warnOutput.length).toBe(1); - expect(warnOutput).toMatch(/^⮑ {3}tmpl.html@3:20/); + expect(warnOutput).toMatch(/^⮑ {3}tmpl\.html@3:20/); const content = tree.readContent('/tmpl.html'); expect(content).toContain(``); @@ -215,9 +215,30 @@ describe('routerlink emptyExpr assignment migration', () => { await runMigration(); expect(warnOutput.length).toBe(1); - expect(warnOutput[0]).toMatch(/^⮑ {3}index.ts@4:35/); + expect(warnOutput[0]).toMatch(/^⮑ {3}index\.ts@4:35/); const content = tree.readContent('/index.ts'); expect(content).toContain(`
\r\n{{1}}\r\n
`); }); + + it('should work for files that use CRLF line endings before routerLink bindings', async () => { + writeFile( + '/index.ts', + ` + import {Component} from '@angular/core'; + + @Component({` + + 'template: `' + + '\r\n\r\n\r\n
{{1}}
`' + + `}) + export class MyComp {} + `); + + await runMigration(); + expect(warnOutput.length).toBe(1); + expect(warnOutput[0]).toMatch(/^⮑ {3}index\.ts@7:6/); + + const content = tree.readContent('/index.ts'); + expect(content).toContain(`\r\n\r\n\r\n
{{1}}
`); + }); }); diff --git a/packages/core/schematics/utils/ng_component_template.ts b/packages/core/schematics/utils/ng_component_template.ts index cc84653e3da..8c2c5c34217 100644 --- a/packages/core/schematics/utils/ng_component_template.ts +++ b/packages/core/schematics/utils/ng_component_template.ts @@ -97,16 +97,24 @@ export class NgComponentTemplateVisitor { if (propertyName === 'template' && ts.isStringLiteralLike(property.initializer)) { // Need to add an offset of one to the start because the template quotes are // not part of the template content. - const templateStartIdx = property.initializer.getStart() + 1; + // The `getText()` method gives us the original raw text. + // We could have used the `text` property, but if the template is defined as a backtick + // string then the `text` property contains a "cooked" version of the string. Such cooked + // strings will have converted CRLF characters to only LF. This messes up string + // replacements in template migrations. + // The raw text returned by `getText()` includes the enclosing quotes so we change the + // `content` and `start` values accordingly. + const content = property.initializer.getText().slice(1, -1); + const start = property.initializer.getStart() + 1; const filePath = resolve(sourceFileName); this.resolvedTemplates.push({ filePath: filePath, container: node, - content: property.initializer.text, + content, inline: true, - start: templateStartIdx, + start: start, getCharacterAndLineOfPosition: pos => - ts.getLineAndCharacterOfPosition(sourceFile, pos + templateStartIdx) + ts.getLineAndCharacterOfPosition(sourceFile, pos + start) }); } if (propertyName === 'templateUrl' && ts.isStringLiteralLike(property.initializer)) {