/
index.ts
147 lines (132 loc) · 4.51 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ComponentMigrator, MIGRATORS} from './rules';
import {
DevkitFileSystem,
UpdateProject,
findStylesheetFiles,
WorkspacePath,
getWorkspaceConfigGracefully,
getTargetTsconfigPath,
} from '@angular/cdk/schematics';
import {Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
import {RuntimeCodeMigration} from './rules/ts-migration/runtime-migration';
import {Schema} from './schema';
import {TemplateMigration} from './rules/template-migration';
import {ThemingStylesMigration} from './rules/theming-styles';
/** Groups of components that must be migrated together. */
const migrationGroups = [
['autocomplete', 'form-field', 'input', 'option', 'optgroup', 'select'],
['button'],
['card'],
['checkbox'],
['chips'],
['dialog'],
['list'],
['menu'],
['paginator'],
['progress-bar'],
['progress-spinner'],
['radio'],
['slide-toggle'],
['slider'],
['snack-bar'],
['table'],
['tabs'],
['tooltip'],
];
function getComponentsToMigrate(requested: string[]): Set<string> {
const componentsToMigrate = new Set<string>(requested);
if (componentsToMigrate.has('all')) {
componentsToMigrate.clear();
migrationGroups.forEach(group =>
group.forEach(component => componentsToMigrate.add(component)),
);
} else {
for (const group of migrationGroups) {
if (group.some(component => componentsToMigrate.has(component))) {
group.forEach(component => componentsToMigrate.add(component));
}
}
}
return componentsToMigrate;
}
function runMigrations(
context: SchematicContext,
fileSystem: DevkitFileSystem,
tsconfigPath: WorkspacePath,
migrators: ComponentMigrator[],
analyzedFiles: Set<WorkspacePath>,
additionalStylesheetPaths: string[],
limitToDirectory?: string,
): boolean {
const program = UpdateProject.createProgramFromTsconfig(tsconfigPath, fileSystem);
const project = new UpdateProject(context, program, fileSystem, analyzedFiles, context.logger);
return !project.migrate(
[ThemingStylesMigration, TemplateMigration, RuntimeCodeMigration],
null,
migrators,
additionalStylesheetPaths,
limitToDirectory,
).hasFailures;
}
export default function (options: Schema): Rule {
return async (tree: Tree, context: SchematicContext) => {
const logger = context.logger;
const workspace = await getWorkspaceConfigGracefully(tree);
if (workspace === null) {
logger.error('Could not find workspace configuration file.');
return;
}
const projectNames = workspace.projects.keys();
const fileSystem = new DevkitFileSystem(tree);
const analyzedFiles = new Set<WorkspacePath>();
const componentsToMigrate = getComponentsToMigrate(options.components);
const migrators = MIGRATORS.filter(m => componentsToMigrate.has(m.component));
let success = true;
if (options.directory) {
logger.info(`Limiting migration to: ${options.directory}`);
}
logger.info(`Migrating components:\n${[...componentsToMigrate].join('\n')}`);
for (const projectName of projectNames) {
const project = workspace.projects.get(projectName)!;
const tsconfigPaths = [
getTargetTsconfigPath(project, 'build'),
getTargetTsconfigPath(project, 'test'),
].filter((p): p is WorkspacePath => !!p);
if (!tsconfigPaths.length) {
logger.warn(
`Skipping migration for project ${projectName}. Unable to determine 'tsconfig.json' file in workspace config.`,
);
continue;
}
const additionalStylesheetPaths = findStylesheetFiles(tree, project.root);
logger.info(`Migrating project: ${projectName}`);
for (const tsconfigPath of tsconfigPaths) {
success &&= runMigrations(
context,
fileSystem,
tsconfigPath,
migrators,
analyzedFiles,
additionalStylesheetPaths,
options.directory || undefined,
);
}
}
// Commit all recorded edits in the update recorder. We apply the edits after all
// migrations ran because otherwise offsets in the TypeScript program would be
// shifted and individual migrations could no longer update the same source file.
fileSystem.commitEdits();
if (!success) {
logger.error('Unable to migrate project. See errors above.');
} else {
logger.info('Successfully migrated the project.');
}
};
}