diff --git a/packages/core/schematics/migrations/injectable-pipe/index.ts b/packages/core/schematics/migrations/injectable-pipe/index.ts
index 5c4615bd90..51c088677b 100644
--- a/packages/core/schematics/migrations/injectable-pipe/index.ts
+++ b/packages/core/schematics/migrations/injectable-pipe/index.ts
@@ -47,7 +47,10 @@ function runInjectablePipeMigration(tree: Tree, tsconfigPath: string, basePath:
// source files, it can end up updating query definitions multiple times.
host.readFile = fileName => {
const buffer = tree.read(relative(basePath, fileName));
- return buffer ? buffer.toString() : undefined;
+ // Strip BOM as otherwise TSC methods (Ex: getWidth) will return an offset which
+ // which breaks the CLI UpdateRecorder.
+ // See: https://github.com/angular/angular/pull/30719
+ return buffer ? buffer.toString().replace(/^\uFEFF/, '') : undefined;
};
const program = ts.createProgram(parsed.fileNames, parsed.options, host);
diff --git a/packages/core/schematics/migrations/move-document/index.ts b/packages/core/schematics/migrations/move-document/index.ts
index ffb2a59079..30d0cc5597 100644
--- a/packages/core/schematics/migrations/move-document/index.ts
+++ b/packages/core/schematics/migrations/move-document/index.ts
@@ -48,7 +48,10 @@ function runMoveDocumentMigration(tree: Tree, tsconfigPath: string, basePath: st
// source files, it can end up updating query definitions multiple times.
host.readFile = fileName => {
const buffer = tree.read(relative(basePath, fileName));
- return buffer ? buffer.toString() : undefined;
+ // Strip BOM as otherwise TSC methods (Ex: getWidth) will return an offset which
+ // which breaks the CLI UpdateRecorder.
+ // See: https://github.com/angular/angular/pull/30719
+ return buffer ? buffer.toString().replace(/^\uFEFF/, '') : undefined;
};
const program = ts.createProgram(parsed.fileNames, parsed.options, host);
diff --git a/packages/core/schematics/migrations/static-queries/index.ts b/packages/core/schematics/migrations/static-queries/index.ts
index a12f1c06ba..207531bbeb 100644
--- a/packages/core/schematics/migrations/static-queries/index.ts
+++ b/packages/core/schematics/migrations/static-queries/index.ts
@@ -125,7 +125,10 @@ function analyzeProject(
// source files, it can end up updating query definitions multiple times.
host.readFile = fileName => {
const buffer = tree.read(relative(basePath, fileName));
- return buffer ? buffer.toString() : undefined;
+ // Strip BOM as otherwise TSC methods (Ex: getWidth) will return an offset which
+ // which breaks the CLI UpdateRecorder.
+ // See: https://github.com/angular/angular/pull/30719
+ return buffer ? buffer.toString().replace(/^\uFEFF/, '') : undefined;
};
const program = ts.createProgram(parsed.fileNames, parsed.options, host);
diff --git a/packages/core/schematics/migrations/template-var-assignment/index.ts b/packages/core/schematics/migrations/template-var-assignment/index.ts
index e6b0ddef48..a7fce2081b 100644
--- a/packages/core/schematics/migrations/template-var-assignment/index.ts
+++ b/packages/core/schematics/migrations/template-var-assignment/index.ts
@@ -53,7 +53,10 @@ function runTemplateVariableAssignmentCheck(
// program to be based on the file contents in the virtual file tree.
host.readFile = fileName => {
const buffer = tree.read(relative(basePath, fileName));
- return buffer ? buffer.toString() : undefined;
+ // Strip BOM as otherwise TSC methods (Ex: getWidth) will return an offset which
+ // which breaks the CLI UpdateRecorder.
+ // See: https://github.com/angular/angular/pull/30719
+ return buffer ? buffer.toString().replace(/^\uFEFF/, '') : undefined;
};
const program = ts.createProgram(parsed.fileNames, parsed.options, host);
diff --git a/packages/core/schematics/test/injectable_pipe_migration_spec.ts b/packages/core/schematics/test/injectable_pipe_migration_spec.ts
index be238ed894..a07732b4e9 100644
--- a/packages/core/schematics/test/injectable_pipe_migration_spec.ts
+++ b/packages/core/schematics/test/injectable_pipe_migration_spec.ts
@@ -60,7 +60,21 @@ describe('injectable pipe migration', () => {
.toMatch(/@Injectable\(\)\s+@Pipe\(\{ name: 'myPipe' \}\)\s+export class MyPipe/);
});
- it('should add an import for Injectable to the @angular/core import declaration', async() => {
+ it('should add @Injectable to pipes that do not have it (BOM)', () => {
+ writeFile('/index.ts', `\uFEFF
+ import { Pipe } from '@angular/core';
+
+ @Pipe({ name: 'myPipe' })
+ export class MyPipe {
+ }
+ `);
+
+ runMigration();
+ expect(tree.readContent('/index.ts'))
+ .toMatch(/@Injectable\(\)\s+@Pipe\(\{ name: 'myPipe' \}\)\s+export class MyPipe/);
+ });
+
+ it('should add an import for Injectable to the @angular/core import declaration', () => {
writeFile('/index.ts', `
import { Pipe } from '@angular/core';
diff --git a/packages/core/schematics/test/move_document_migration_spec.ts b/packages/core/schematics/test/move_document_migration_spec.ts
index f7093e6785..066f04a122 100644
--- a/packages/core/schematics/test/move_document_migration_spec.ts
+++ b/packages/core/schematics/test/move_document_migration_spec.ts
@@ -60,7 +60,20 @@ describe('move-document migration', () => {
expect(content).not.toContain(`import {DOCUMENT} from '@angular/platform-browser';`);
});
- it('should properly apply import replacement with existing import', async() => {
+ it('should properly apply import replacement (BOM)', () => {
+ writeFile('/index.ts', `\uFEFF
+ import {DOCUMENT} from '@angular/platform-browser';
+ `);
+
+ runMigration();
+
+ const content = tree.readContent('/index.ts');
+
+ expect(content).toContain(`import { DOCUMENT } from "@angular/common";`);
+ expect(content).not.toContain(`import {DOCUMENT} from '@angular/platform-browser';`);
+ });
+
+ it('should properly apply import replacement with existing import', () => {
writeFile('/index.ts', `
import {DOCUMENT} from '@angular/platform-browser';
import {someImport} from '@angular/common';
diff --git a/packages/core/schematics/test/static_queries_migration_template_spec.ts b/packages/core/schematics/test/static_queries_migration_template_spec.ts
index bafd77b11f..89956ce4dc 100644
--- a/packages/core/schematics/test/static_queries_migration_template_spec.ts
+++ b/packages/core/schematics/test/static_queries_migration_template_spec.ts
@@ -158,6 +158,29 @@ describe('static-queries migration with template strategy', () => {
.toContain(`@ViewChild('myTmpl', { static: true }) query: any;`);
});
+ it('should detect queries selecting ng-template as static (BOM)', async() => {
+ writeFile('/index.ts', `\uFEFF
+ import {Component, NgModule, ViewChild} from '@angular/core';
+
+ @Component({template: \`
+
+ My template
+
+ \`})
+ export class MyComp {
+ private @ViewChild('myTmpl') query: any;
+ }
+
+ @NgModule({declarations: [MyComp]})
+ export class MyModule {}
+ `);
+
+ await runMigration();
+
+ expect(tree.readContent('/index.ts'))
+ .toContain(`@ViewChild('myTmpl', { static: true }) query: any;`);
+ });
+
it('should detect queries selecting component view providers through string token', async() => {
writeFile('/index.ts', `
import {Component, Directive, NgModule, ViewChild} from '@angular/core';
diff --git a/packages/core/schematics/test/static_queries_migration_usage_spec.ts b/packages/core/schematics/test/static_queries_migration_usage_spec.ts
index c1e065276f..02946c884d 100644
--- a/packages/core/schematics/test/static_queries_migration_usage_spec.ts
+++ b/packages/core/schematics/test/static_queries_migration_usage_spec.ts
@@ -127,6 +127,26 @@ describe('static-queries migration with usage strategy', () => {
.toContain(`@ContentChild('test', { static: false }) query: any;`);
});
+ it('should not mark content queries used in "ngAfterContentInit" as static (BOM)', async() => {
+ writeFile('/index.ts', `\uFEFF
+ import {Component, ContentChild} from '@angular/core';
+
+ @Component({template: ''})
+ export class MyComp {
+ @ContentChild('test') query: any;
+
+ ngAfterContentInit() {
+ this.query.classList.add('test');
+ }
+ }
+ `);
+
+ await runMigration();
+
+ expect(tree.readContent('/index.ts'))
+ .toContain(`@ContentChild('test', { static: false }) query: any;`);
+ });
+
it('should not mark content queries used in "ngAfterContentChecked" as static', async() => {
writeFile('/index.ts', `
import {Component, ContentChild} from '@angular/core';