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)) {