Skip to content

Commit f24a49f

Browse files
wagnermacielmmalerba
authored andcommitted
feat(material/schematics): initial setup for template migrations (#24515)
* feat(material/schematics): initial setup for template migrations * created TemplateMigration for migrating templates * added it to the migrations for the mdc-migration schematic
1 parent a12f268 commit f24a49f

File tree

5 files changed

+83
-1
lines changed

5 files changed

+83
-1
lines changed

src/material/schematics/ng-generate/mdc-migration/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ ts_library(
1616
deps = [
1717
"//src/cdk/schematics",
1818
"@npm//@angular-devkit/schematics",
19+
"@npm//@angular/compiler",
1920
"@npm//@types/node",
2021
"@npm//postcss",
2122
"@npm//postcss-scss",

src/material/schematics/ng-generate/mdc-migration/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
1010
import {Schema} from './schema';
1111
import {DevkitFileSystem, UpdateProject, findStylesheetFiles} from '@angular/cdk/schematics';
1212
import {ThemingStylesMigration} from './rules/theming-styles';
13+
import {TemplateMigration} from './rules/template-migration';
1314
import {MIGRATORS} from './rules';
1415
import {dirname} from 'path';
1516
import {StyleMigrator} from './rules/style-migrator';
@@ -78,7 +79,7 @@ export default function (options: Schema): Rule {
7879
const additionalStylesheetPaths = findStylesheetFiles(tree, migrationDir);
7980
const project = new UpdateProject(context, program, fileSystem, new Set(), context.logger);
8081
const {hasFailures} = project.migrate(
81-
[ThemingStylesMigration],
82+
[ThemingStylesMigration, TemplateMigration],
8283
null,
8384
migrators,
8485
additionalStylesheetPaths,

src/material/schematics/ng-generate/mdc-migration/rules/components/test-setup-helper.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {runfiles} from '@bazel/runfiles';
1212
const TS_CONFIG = '/projects/material/tsconfig.app.json';
1313

1414
export const THEME_FILE = '/projects/material/src/theme.scss';
15+
export const TEMPLATE_FILE = '/projects/material/src/app/app.component.html';
1516

1617
export function createNewTestRunner(): SchematicTestRunner {
1718
return new SchematicTestRunner(
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {createTestApp, patchDevkitTreeToExposeTypeScript} from '@angular/cdk/schematics/testing';
2+
import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing';
3+
import {createNewTestRunner, migrateComponent, TEMPLATE_FILE} from './components/test-setup-helper';
4+
5+
describe('template migrations', () => {
6+
let runner: SchematicTestRunner;
7+
let cliAppTree: UnitTestTree;
8+
9+
async function runMigrationTest(oldFileContent: string, newFileContent: string) {
10+
cliAppTree.overwrite(TEMPLATE_FILE, oldFileContent);
11+
const tree = await migrateComponent('card', runner, cliAppTree);
12+
expect(tree.readContent(TEMPLATE_FILE)).toBe(newFileContent);
13+
}
14+
15+
beforeEach(async () => {
16+
runner = createNewTestRunner();
17+
cliAppTree = patchDevkitTreeToExposeTypeScript(await createTestApp(runner));
18+
});
19+
20+
it('should do nothing yet', async () => {
21+
await runMigrationTest('<h1>Hello</h1>', '<h1>Hello</h1>');
22+
});
23+
});
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Migration, ResolvedResource} from '@angular/cdk/schematics';
10+
import {SchematicContext} from '@angular-devkit/schematics';
11+
import {StyleMigrator} from './style-migrator';
12+
import * as compiler from '@angular/compiler';
13+
14+
/**
15+
* Traverses the given tree of nodes and runs the given callbacks for each Element node encountered.
16+
*
17+
* Note that updates to the start tags of html element should be done in the postorder callback,
18+
* and updates to the end tags of html elements should be done in the preorder callback to avoid
19+
* issues with line collisions.
20+
*
21+
* @param nodes The nodes of the ast from a parsed template.
22+
* @param preorderCallback A function that gets run for each Element node in a preorder traversal.
23+
* @param postorderCallback A function that gets run for each Element node in a postorder traversal.
24+
*/
25+
function visitElements(
26+
nodes: compiler.TmplAstNode[],
27+
preorderCallback: (node: compiler.TmplAstElement) => void = () => {},
28+
postorderCallback: (node: compiler.TmplAstElement) => void = () => {},
29+
): void {
30+
for (let i = 0; i < nodes.length; i++) {
31+
const node = nodes[i];
32+
if (node instanceof compiler.TmplAstElement) {
33+
preorderCallback(node);
34+
visitElements(node.children, preorderCallback, postorderCallback);
35+
postorderCallback(node);
36+
}
37+
}
38+
}
39+
40+
export class TemplateMigration extends Migration<StyleMigrator[], SchematicContext> {
41+
enabled = true;
42+
43+
override visitTemplate(template: ResolvedResource) {
44+
const ast = compiler.parseTemplate(template.content, template.filePath, {
45+
preserveWhitespaces: true,
46+
preserveLineEndings: true,
47+
leadingTriviaChars: [],
48+
});
49+
50+
visitElements(ast.nodes, node => {
51+
// TODO(wagnermaciel): implement the migration updates.
52+
});
53+
54+
this.fileSystem.overwrite(template.filePath, template.content);
55+
}
56+
}

0 commit comments

Comments
 (0)