Skip to content

Commit e8fec55

Browse files
committed
Address feedback
1 parent bb54ff1 commit e8fec55

16 files changed

+115
-60
lines changed

src/cdk/schematics/ng-update/devkit-file-system.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import {Tree, UpdateRecorder} from '@angular-devkit/schematics';
1111
import {relative} from 'path';
1212
import {FileSystem} from '../update-tool/file-system';
1313

14-
/** File system that leverages the virtual tree from the CLI devkit. */
14+
/**
15+
* File system that leverages the virtual tree from the CLI devkit. This file
16+
* system is commonly used by `ng update` migrations that run as part of the
17+
* Angular CLI.
18+
*/
1519
export class DevkitFileSystem implements FileSystem {
1620
private _updateRecorderCache = new Map<string, UpdateRecorder>();
1721

src/cdk/schematics/ng-update/devkit-migration-rule.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {NodePackageInstallTask} from '@angular-devkit/schematics/tasks';
1111
import {WorkspaceProject} from '@schematics/angular/utility/workspace-models';
1212
import {sync as globSync} from 'glob';
1313
import {join} from 'path';
14+
import {DevkitMigration, MigrationCtor} from '..';
1415

1516
import {UpdateProject} from '../update-tool';
1617
import {TargetVersion} from '../update-tool/target-version';
@@ -33,7 +34,7 @@ import {UpgradeData} from './upgrade-data';
3334

3435

3536
/** List of migrations which run for the CDK update. */
36-
export const cdkMigrations: DevkitMigrationCtor<UpgradeData>[] = [
37+
export const cdkMigrations: MigrationCtor<UpgradeData>[] = [
3738
AttributeSelectorsMigration,
3839
ClassInheritanceMigration,
3940
ClassNamesMigration,
@@ -47,7 +48,7 @@ export const cdkMigrations: DevkitMigrationCtor<UpgradeData>[] = [
4748
PropertyNamesMigration,
4849
];
4950

50-
type NullableMigration = DevkitMigrationCtor<UpgradeData|null>;
51+
export type NullableDevkitMigration = MigrationCtor<UpgradeData|null, DevkitContext>;
5152

5253
type PostMigrationFn =
5354
(context: SchematicContext, targetVersion: TargetVersion, hasFailure: boolean) => void;
@@ -57,8 +58,8 @@ type PostMigrationFn =
5758
* specified target version.
5859
*/
5960
export function createMigrationSchematicRule(
60-
targetVersion: TargetVersion, extraMigrations: NullableMigration[], upgradeData: UpgradeData,
61-
onMigrationCompleteFn?: PostMigrationFn): Rule {
61+
targetVersion: TargetVersion, extraMigrations: NullableDevkitMigration[],
62+
upgradeData: UpgradeData, onMigrationCompleteFn?: PostMigrationFn): Rule {
6263
return async (tree: Tree, context: SchematicContext) => {
6364
const logger = context.logger;
6465
const workspace = getWorkspaceConfigGracefully(tree);
@@ -76,7 +77,7 @@ export function createMigrationSchematicRule(
7677
const workspaceFsPath = process.cwd();
7778
const fileSystem = new DevkitFileSystem(tree, workspaceFsPath);
7879
const projectNames = Object.keys(workspace.projects);
79-
const migrations: NullableMigration[] = [...cdkMigrations, ...extraMigrations];
80+
const migrations: NullableDevkitMigration[] = [...cdkMigrations, ...extraMigrations];
8081
let hasFailures = false;
8182

8283
for (const projectName of projectNames) {
@@ -89,18 +90,19 @@ export function createMigrationSchematicRule(
8990
continue;
9091
}
9192
if (buildTsconfigPath !== null) {
92-
runMigrations(project, buildTsconfigPath, false);
93+
runMigrations(project, projectName, buildTsconfigPath, false);
9394
}
9495
if (testTsconfigPath !== null) {
95-
runMigrations(project, testTsconfigPath, true);
96+
runMigrations(project, projectName, testTsconfigPath, true);
9697
}
9798
}
9899

99100
let runPackageManager = false;
100-
// Run the global post migration static members for all migrations.
101+
// Run the global post migration static members for all
102+
// registered devkit migrations.
101103
migrations.forEach(m => {
102-
const actionResult =
103-
m.globalPostMigration !== undefined ? m.globalPostMigration(tree, context) : null;
104+
const actionResult = isDevkitMigration(m) && m.globalPostMigration !== undefined ?
105+
m.globalPostMigration(tree, context) : null;
104106
if (actionResult) {
105107
runPackageManager = runPackageManager || actionResult.runPackageManager;
106108
}
@@ -119,13 +121,15 @@ export function createMigrationSchematicRule(
119121
}
120122

121123
/** Runs the migrations for the specified workspace project. */
122-
function runMigrations(project: WorkspaceProject, tsconfigPath: string, isTestTarget: boolean) {
124+
function runMigrations(project: WorkspaceProject, projectName: string,
125+
tsconfigPath: string, isTestTarget: boolean) {
123126
const projectRootFsPath = join(workspaceFsPath, project.root);
124127
const tsconfigFsPath = join(workspaceFsPath, tsconfigPath);
125128
const program = UpdateProject.createProgramFromTsconfig(tsconfigFsPath, fileSystem);
126129
const updateContext: DevkitContext = {
127130
workspaceFsPath,
128131
isTestTarget,
132+
projectName,
129133
project,
130134
tree,
131135
};
@@ -159,3 +163,9 @@ export function createMigrationSchematicRule(
159163
}
160164
};
161165
}
166+
167+
/** Whether the given migration type refers to a devkit migration */
168+
export function isDevkitMigration(value: MigrationCtor<any, any>)
169+
: value is DevkitMigrationCtor<any> {
170+
return DevkitMigration.isPrototypeOf(value);
171+
}

src/cdk/schematics/ng-update/devkit-migration.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import {Constructor, Migration, PostMigrationAction} from '../update-tool/migrat
1313
export type DevkitContext = {
1414
/** Devkit tree for the current migrations. Can be used to insert/remove files. */
1515
tree: Tree,
16+
/** Name of the project the migrations run against. */
17+
projectName: string;
1618
/** Workspace project the migrations run against. */
1719
project: WorkspaceProject,
1820
/** Absolute file system path to the workspace */
@@ -22,6 +24,13 @@ export type DevkitContext = {
2224
};
2325

2426
export abstract class DevkitMigration<Data> extends Migration<Data, DevkitContext> {
27+
28+
/** Prints an informative message with context on the current target. */
29+
protected printInfo(text: string) {
30+
const targetName = this.context.isTestTarget ? 'test' : 'build';
31+
this.logger.info(`- ${this.context.projectName}@${targetName}: ${text}`);
32+
}
33+
2534
/**
2635
* Optional static method that will be called once the migration of all project
2736
* targets has been performed. This method can be used to make changes respecting the

src/cdk/schematics/ng-update/test-cases/misc/global-stylesheets.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1+
import {resolveBazelPath} from '@angular/cdk/schematics/testing';
12
import {readFileSync} from 'fs';
2-
import {resolveBazel} from '@angular/cdk/schematics/testing';
33
import {MIGRATION_PATH} from '../../../index.spec';
44
import {createTestCaseSetup} from '../../../testing';
55

66
describe('global stylesheets migration', () => {
77

88
it('should not check stylesheet twice if referenced in component', async () => {
99
const {runFixers, writeFile, removeTempDir, appTree} = await createTestCaseSetup(
10-
'migration-v6', MIGRATION_PATH, [resolveBazel(__dirname, './global-stylesheets_input.ts')]);
10+
'migration-v6', MIGRATION_PATH,
11+
[resolveBazelPath(__dirname, './global-stylesheets_input.ts')]);
1112

1213
const testStylesheetPath = 'projects/cdk-testing/src/test-cases/global-stylesheets-test.scss';
1314

1415
// Copy the test stylesheets file into the test CLI application. That way it will
1516
// be picked up by the update-tool.
1617
writeFile(testStylesheetPath,
17-
readFileSync(resolveBazel(__dirname, './global-stylesheets-test.scss'), 'utf8'));
18+
readFileSync(resolveBazelPath(__dirname, './global-stylesheets-test.scss'), 'utf8'));
1819
writeFile('/projects/cdk-testing/third_party/materialize.css/bundle.css', '');
1920

2021
await runFixers();

src/cdk/schematics/ng-update/test-cases/misc/method-call-checks.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import {resolveBazel} from '@angular/cdk/schematics/testing';
1+
import {resolveBazelPath} from '@angular/cdk/schematics/testing';
22
import {MIGRATION_PATH} from '../../../index.spec';
33
import {createTestCaseSetup} from '../../../testing';
44

55
describe('v6 method call checks', () => {
66
it('should properly report invalid method calls', async () => {
77
const {runFixers, removeTempDir} = await createTestCaseSetup(
8-
'migration-v6', MIGRATION_PATH, [resolveBazel(__dirname, './method-call-checks_input.ts')]);
8+
'migration-v6', MIGRATION_PATH,
9+
[resolveBazelPath(__dirname, './method-call-checks_input.ts')]);
910

1011
const {logOutput} = await runFixers();
1112

src/cdk/schematics/testing/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ export * from './post-scheduled-tasks';
1010
export * from './test-app';
1111
export * from './test-case-setup';
1212
export * from './file-content';
13-
export * from './resolve-bazel';
13+
export * from './resolve-bazel-path';

src/cdk/schematics/testing/resolve-bazel.ts renamed to src/cdk/schematics/testing/resolve-bazel-path.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import * as path from 'path';
1212
* Resolves a given path through Bazel while respecting the specified parent directory.
1313
* Usually `require.resolve` could just be used for resolving runfiles relatively, but support
1414
* for this has been removed and absolute manifest paths or the runfile helpers are now needed
15-
* on Windows. This helper provides a resolution method that works similar on all platforms.
15+
* on Windows. This helper provides a resolution method that works the same on all platforms.
1616
*/
17-
export function resolveBazel(parent: string, relativePath: string) {
17+
export function resolveBazelPath(parent: string, relativePath: string) {
1818
if (process.env['RUNFILES_MANIFEST_ONLY'] !== '1') {
1919
return path.join(parent, relativePath);
2020
}

src/cdk/schematics/update-tool/index.ts

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,27 +42,28 @@ export class UpdateProject<Context> {
4242
*/
4343
migrate<Data>(migrationTypes: MigrationCtor<Data, Context>[], target: TargetVersion, data: Data,
4444
additionalStylesheetPaths?: string[]): {hasFailures: boolean} {
45-
const migrations: Migration<Data, Context>[] = [];
46-
47-
// Create instances of all specified migrations.
48-
for (const ctor of migrationTypes) {
49-
const instance = new ctor(this._program, this._typeChecker, target, this._context,
50-
data, this._fileSystem, this._logger);
51-
instance.init();
52-
if (instance.enabled) {
53-
migrations.push(instance);
54-
}
55-
}
56-
45+
// Create instances of the specified migrations.
46+
const migrations = this._createMigrations(migrationTypes, target, data);
47+
// Creates the component resource collector. The collector can visit arbitrary
48+
// TypeScript nodes and will find Angular component resources. Resources include
49+
// templates and stylesheets. It also captures inline stylesheets and templates.
50+
const resourceCollector = new ComponentResourceCollector(this._typeChecker, this._fileSystem);
51+
// Collect all of the TypeScript source files we want to migrate. We don't
52+
// migrate type definition files, or source files from external libraries.
5753
const sourceFiles = this._program.getSourceFiles().filter(
5854
f => !f.isDeclarationFile && !this._program.isSourceFileFromExternalLibrary(f));
59-
const resourceCollector = new ComponentResourceCollector(this._typeChecker, this._fileSystem);
55+
56+
// Helper function that visits a given TypeScript node and collects all referenced
57+
// component resources (i.e. stylesheets or templates). Additionally, the helper
58+
// visits the node in each instantiated migration.
6059
const visitNodeAndCollectResources = (node: ts.Node) => {
6160
migrations.forEach(r => r.visitNode(node));
6261
ts.forEachChild(node, visitNodeAndCollectResources);
6362
resourceCollector.visitNode(node);
6463
};
6564

65+
// Walk through all source file, if it has not been visited before, and
66+
// visit found nodes while collecting potential resources.
6667
sourceFiles.forEach(sourceFile => {
6768
const resolvedPath = this._fileSystem.resolve(sourceFile.fileName);
6869
// Do not visit source files which have been checked as part of a
@@ -73,6 +74,9 @@ export class UpdateProject<Context> {
7374
}
7475
});
7576

77+
// Walk through all resolved templates and visit them in each instantiated
78+
// migration. Note that this can only happen after source files have been
79+
// visited because we find templates through the TypeScript source files.
7680
resourceCollector.resolvedTemplates.forEach(template => {
7781
const resolvedPath = this._fileSystem.resolve(template.filePath);
7882
// Do not visit the template if it has been checked before. Inline
@@ -83,6 +87,9 @@ export class UpdateProject<Context> {
8387
}
8488
});
8589

90+
// Walk through all resolved stylesheets and visit them in each instantiated
91+
// migration. Note that this can only happen after source files have been
92+
// visited because we find stylesheets through the TypeScript source files.
8693
resourceCollector.resolvedStylesheets.forEach(stylesheet => {
8794
const resolvedPath = this._fileSystem.resolve(stylesheet.filePath);
8895
// Do not visit the stylesheet if it has been checked before. Inline
@@ -93,8 +100,10 @@ export class UpdateProject<Context> {
93100
}
94101
});
95102

96-
// In some applications, developers will have global stylesheets which are not specified
97-
// in any Angular component. Therefore we allow for additional stylesheets being specified.
103+
// In some applications, developers will have global stylesheets which are not
104+
// specified in any Angular component. Therefore we allow for additional stylesheets
105+
// being specified. We visit them in each migration unless they have been already
106+
// discovered before as actual component resource.
98107
additionalStylesheetPaths.forEach(filePath => {
99108
const stylesheet = resourceCollector.resolveExternalStylesheet(filePath, null);
100109
const resolvedPath = this._fileSystem.resolve(filePath);
@@ -126,6 +135,24 @@ export class UpdateProject<Context> {
126135
};
127136
}
128137

138+
/**
139+
* Creates instances of the given migrations with the specified target
140+
* version and data.
141+
*/
142+
private _createMigrations<Data>(types: MigrationCtor<Data, Context>[], target: TargetVersion,
143+
data: Data): Migration<Data, Context>[] {
144+
const result: Migration<Data, Context>[] = [];
145+
for (const ctor of types) {
146+
const instance = new ctor(this._program, this._typeChecker, target, this._context,
147+
data, this._fileSystem, this._logger);
148+
instance.init();
149+
if (instance.enabled) {
150+
result.push(instance);
151+
}
152+
}
153+
return result;
154+
}
155+
129156
/**
130157
* Creates a program form the specified tsconfig and patches the host
131158
* to read files through the given file system.

src/cdk/schematics/update-tool/migration.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,4 @@ export abstract class Migration<Data, Context = never> {
8484
message: message,
8585
});
8686
}
87-
88-
/** Prints the given message with "info" loglevel. */
89-
printInfo(text: string) {
90-
// TODO: FIND REPLACEMENT???
91-
this.logger.info(`- ${text}`);
92-
}
9387
}

src/material/schematics/ng-update/index.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@
99
import {Rule, SchematicContext} from '@angular-devkit/schematics';
1010
import {
1111
createMigrationSchematicRule,
12-
DevkitMigrationCtor,
13-
TargetVersion,
14-
UpgradeData
12+
NullableDevkitMigration,
13+
TargetVersion
1514
} from '@angular/cdk/schematics';
1615
import {HammerGesturesMigration} from './migrations/hammer-gestures-v9/hammer-gestures-migration';
1716
import {MiscClassInheritanceMigration} from './migrations/misc-checks/misc-class-inheritance';
@@ -28,7 +27,7 @@ import {
2827

2928
import {materialUpgradeData} from './upgrade-data';
3029

31-
const materialMigrations: DevkitMigrationCtor<UpgradeData|null>[] = [
30+
const materialMigrations: NullableDevkitMigration[] = [
3231
MiscClassInheritanceMigration,
3332
MiscClassNamesMigration,
3433
MiscImportsMigration,

src/material/schematics/ng-update/test-cases/misc/class-inheritance.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import {createTestCaseSetup, resolveBazel} from '@angular/cdk/schematics/testing';
1+
import {createTestCaseSetup, resolveBazelPath} from '@angular/cdk/schematics/testing';
22
import {MIGRATION_PATH} from '../../../index.spec';
33

44
describe('class inheritance misc checks', () => {
55
describe('v6 class which extends MatFormFieldControl', () => {
66
it('should report if class does not declare "shouldLabelFloat"', async () => {
77
const {removeTempDir, runFixers} = await createTestCaseSetup(
8-
'migration-v6', MIGRATION_PATH, [resolveBazel(__dirname, './class-inheritance_input.ts')]);
8+
'migration-v6', MIGRATION_PATH,
9+
[resolveBazelPath(__dirname, './class-inheritance_input.ts')]);
910

1011
const {logOutput} = await runFixers();
1112

src/material/schematics/ng-update/test-cases/misc/constructor-checks.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import {createTestCaseSetup, resolveBazel} from '@angular/cdk/schematics/testing';
1+
import {createTestCaseSetup, resolveBazelPath} from '@angular/cdk/schematics/testing';
22
import {MIGRATION_PATH} from '../../../index.spec';
33

44
describe('constructor checks', () => {
55
it('should properly report invalid constructor expression signatures', async () => {
66
const {removeTempDir, runFixers} = await createTestCaseSetup(
7-
'migration-v6', MIGRATION_PATH, [resolveBazel(__dirname, './constructor-checks_input.ts')]);
7+
'migration-v6', MIGRATION_PATH,
8+
[resolveBazelPath(__dirname, './constructor-checks_input.ts')]);
89

910
const {logOutput} = await runFixers();
1011

src/material/schematics/ng-update/test-cases/misc/import-checks.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import {createTestCaseSetup, resolveBazel} from '@angular/cdk/schematics/testing';
1+
import {createTestCaseSetup, resolveBazelPath} from '@angular/cdk/schematics/testing';
22
import {MIGRATION_PATH} from '../../../index.spec';
33

44
describe('v6 import misc checks', () => {
55
it('should report imports for deleted animation constants', async () => {
66
const {removeTempDir, runFixers} = await createTestCaseSetup(
7-
'migration-v6', MIGRATION_PATH, [resolveBazel(__dirname, './import-checks_input.ts')]);
7+
'migration-v6', MIGRATION_PATH, [resolveBazelPath(__dirname, './import-checks_input.ts')]);
88

99
const {logOutput} = await runFixers();
1010

src/material/schematics/ng-update/test-cases/v8/misc/material-imports.spec.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
import {createTestCaseSetup, readFileContent, resolveBazel} from '@angular/cdk/schematics/testing';
1+
import {
2+
createTestCaseSetup,
3+
readFileContent,
4+
resolveBazelPath
5+
} from '@angular/cdk/schematics/testing';
26
import {MIGRATION_PATH} from '../../../../index.spec';
37

48
describe('v8 material imports', () => {
59
it('should re-map top-level material imports to the proper entry points', async () => {
610
const {runFixers, appTree, writeFile, removeTempDir} = await createTestCaseSetup(
7-
'migration-v8', MIGRATION_PATH, [resolveBazel(__dirname, './material-imports_input.ts')]);
11+
'migration-v8', MIGRATION_PATH,
12+
[resolveBazelPath(__dirname, './material-imports_input.ts')]);
813
const materialPath = '/node_modules/@angular/material';
914

1015
writeFile(`${materialPath}/index.d.ts`, `
@@ -28,7 +33,8 @@ describe('v8 material imports', () => {
2833
await runFixers();
2934

3035
expect(appTree.readContent('/projects/cdk-testing/src/test-cases/material-imports_input.ts'))
31-
.toBe(readFileContent(resolveBazel(__dirname, './material-imports_expected_output.ts')));
36+
.toBe(readFileContent(
37+
resolveBazelPath(__dirname, './material-imports_expected_output.ts')));
3238

3339
removeTempDir();
3440
});

0 commit comments

Comments
 (0)