Skip to content

Commit cb72123

Browse files
wagnermacielmmalerba
authored andcommitted
feat(material/schematics): set up a system for migrating scss (#24326)
* also implements the migrator for the button
1 parent 2959ba0 commit cb72123

File tree

8 files changed

+428
-44
lines changed

8 files changed

+428
-44
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ ts_library(
1717
"//src/cdk/schematics",
1818
"@npm//@angular-devkit/schematics",
1919
"@npm//@types/node",
20+
"@npm//postcss",
21+
"@npm//postcss-scss",
2022
],
2123
)
2224

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ 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 {MIGRATORS} from './rules';
1314
import {dirname} from 'path';
15+
import {StyleMigrator} from './rules/style-migrator';
1416

1517
/** Groups of components that must be migrated together. */
1618
const migrationGroups = [
@@ -59,6 +61,13 @@ export default function (options: Schema): Rule {
5961
console.log('Migrating:', [...componentsToMigrate]);
6062
console.log('Directory:', migrationDir);
6163

64+
const migrators: StyleMigrator[] = [];
65+
for (let i = 0; i < MIGRATORS.length; i++) {
66+
if (componentsToMigrate.has(MIGRATORS[i].component)) {
67+
migrators.push(MIGRATORS[i]);
68+
}
69+
}
70+
6271
return (tree: Tree, context: SchematicContext) => {
6372
const fileSystem = new DevkitFileSystem(tree);
6473
const program = UpdateProject.createProgramFromTsconfig(
@@ -71,7 +80,7 @@ export default function (options: Schema): Rule {
7180
const {hasFailures} = project.migrate(
7281
[ThemingStylesMigration],
7382
null,
74-
null,
83+
migrators,
7584
additionalStylesheetPaths,
7685
);
7786

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
import {createTestApp, patchDevkitTreeToExposeTypeScript} from '@angular/cdk/schematics/testing';
2+
import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing';
3+
import {Schema} from '../schema';
4+
import {runfiles} from '@bazel/runfiles';
5+
6+
describe('button styles', () => {
7+
let runner: SchematicTestRunner;
8+
let cliAppTree: UnitTestTree;
9+
const tsconfig = '/projects/material/tsconfig.app.json';
10+
const themeFile = '/projects/material/src/theme.scss';
11+
12+
async function runMigrationTest(oldFileContent: string, newFileContent: string) {
13+
cliAppTree.create(themeFile, oldFileContent);
14+
const tree = await migrate({tsconfig, components: ['button']});
15+
expect(tree.readContent(themeFile)).toBe(newFileContent);
16+
}
17+
18+
beforeEach(async () => {
19+
runner = new SchematicTestRunner(
20+
'@angular/material',
21+
runfiles.resolveWorkspaceRelative('src/material/schematics/collection.json'),
22+
);
23+
cliAppTree = patchDevkitTreeToExposeTypeScript(await createTestApp(runner));
24+
});
25+
26+
async function migrate(options: Schema): Promise<UnitTestTree> {
27+
return await runner.runSchematicAsync('mdcMigration', options, cliAppTree).toPromise();
28+
}
29+
30+
describe('mixin migrations', () => {
31+
it('should replace the old theme with the new ones', async () => {
32+
await runMigrationTest(
33+
`
34+
@use '@angular/material' as mat;
35+
$theme: ();
36+
@include mat.button-theme($theme);
37+
`,
38+
`
39+
@use '@angular/material' as mat;
40+
$theme: ();
41+
@include mat.mdc-button-theme($theme);
42+
@include mat.mdc-button-typography($theme);
43+
@include mat.mdc-fab-theme($theme);
44+
@include mat.mdc-fab-typography($theme);
45+
@include mat.mdc-icon-theme($theme);
46+
@include mat.mdc-icon-typography($theme);
47+
`,
48+
);
49+
});
50+
51+
it('should use the correct namespace', async () => {
52+
await runMigrationTest(
53+
`
54+
@use '@angular/material' as arbitrary;
55+
$theme: ();
56+
@include arbitrary.button-theme($theme);
57+
`,
58+
`
59+
@use '@angular/material' as arbitrary;
60+
$theme: ();
61+
@include arbitrary.mdc-button-theme($theme);
62+
@include arbitrary.mdc-button-typography($theme);
63+
@include arbitrary.mdc-fab-theme($theme);
64+
@include arbitrary.mdc-fab-typography($theme);
65+
@include arbitrary.mdc-icon-theme($theme);
66+
@include arbitrary.mdc-icon-typography($theme);
67+
`,
68+
);
69+
});
70+
71+
it('should handle updating multiple themes', async () => {
72+
await runMigrationTest(
73+
`
74+
@use '@angular/material' as mat;
75+
$light-theme: ();
76+
$dark-theme: ();
77+
@include mat.button-theme($light-theme);
78+
@include mat.button-theme($dark-theme);
79+
`,
80+
`
81+
@use '@angular/material' as mat;
82+
$light-theme: ();
83+
$dark-theme: ();
84+
@include mat.mdc-button-theme($light-theme);
85+
@include mat.mdc-button-typography($light-theme);
86+
@include mat.mdc-fab-theme($light-theme);
87+
@include mat.mdc-fab-typography($light-theme);
88+
@include mat.mdc-icon-theme($light-theme);
89+
@include mat.mdc-icon-typography($light-theme);
90+
@include mat.mdc-button-theme($dark-theme);
91+
@include mat.mdc-button-typography($dark-theme);
92+
@include mat.mdc-fab-theme($dark-theme);
93+
@include mat.mdc-fab-typography($dark-theme);
94+
@include mat.mdc-icon-theme($dark-theme);
95+
@include mat.mdc-icon-typography($dark-theme);
96+
`,
97+
);
98+
});
99+
100+
it('should preserve whitespace', async () => {
101+
await runMigrationTest(
102+
`
103+
@use '@angular/material' as mat;
104+
$theme: ();
105+
106+
107+
@include mat.button-theme($theme);
108+
109+
110+
`,
111+
`
112+
@use '@angular/material' as mat;
113+
$theme: ();
114+
115+
116+
@include mat.mdc-button-theme($theme);
117+
@include mat.mdc-button-typography($theme);
118+
@include mat.mdc-fab-theme($theme);
119+
@include mat.mdc-fab-typography($theme);
120+
@include mat.mdc-icon-theme($theme);
121+
@include mat.mdc-icon-typography($theme);
122+
123+
124+
`,
125+
);
126+
});
127+
});
128+
129+
describe('selector migrations', () => {
130+
it('should update the legacy mat-button classname', async () => {
131+
await runMigrationTest(
132+
`
133+
.mat-button {
134+
padding: 50px;
135+
}
136+
`,
137+
`
138+
.mat-mdc-button {
139+
padding: 50px;
140+
}
141+
`,
142+
);
143+
});
144+
145+
it('should update multiple legacy classnames', async () => {
146+
await runMigrationTest(
147+
`
148+
.mat-button {
149+
padding: 50px;
150+
}
151+
.mat-button-base {
152+
padding: 25px;
153+
}
154+
`,
155+
`
156+
.mat-mdc-button {
157+
padding: 50px;
158+
}
159+
.mat-mdc-button-base {
160+
padding: 25px;
161+
}
162+
`,
163+
);
164+
});
165+
166+
it('should update a legacy classname w/ multiple selectors', async () => {
167+
await runMigrationTest(
168+
`
169+
.some-class.mat-button, .another-class {
170+
padding: 50px;
171+
}
172+
`,
173+
`
174+
.some-class.mat-mdc-button, .another-class {
175+
padding: 50px;
176+
}
177+
`,
178+
);
179+
});
180+
181+
it('should preserve the whitespace of multiple selectors', async () => {
182+
await runMigrationTest(
183+
`
184+
.some-class,
185+
.mat-button,
186+
.another-class { padding: 50px; }
187+
`,
188+
`
189+
.some-class,
190+
.mat-mdc-button,
191+
.another-class { padding: 50px; }
192+
`,
193+
);
194+
});
195+
});
196+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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 {ClassNameChange, StyleMigrator} from './style-migrator';
10+
11+
export class ButtonStylesMigrator extends StyleMigrator {
12+
component = 'button';
13+
14+
mixinChanges = [
15+
{
16+
old: 'button-theme',
17+
new: [
18+
'mdc-button-theme',
19+
'mdc-button-typography',
20+
'mdc-fab-theme',
21+
'mdc-fab-typography',
22+
'mdc-icon-theme',
23+
'mdc-icon-typography',
24+
],
25+
},
26+
];
27+
28+
classChanges: ClassNameChange[] = [
29+
{old: '.mat-button-base', new: '.mat-mdc-button-base'},
30+
{old: '.mat-button', new: '.mat-mdc-button'},
31+
{old: '.mat-raised-button', new: '.mat-mdc-raised-button'},
32+
{old: '.mat-icon-button', new: '.mat-mdc-icon-button'},
33+
{old: '.mat-fab', new: '.mat-mdc-fab'},
34+
{old: '.mat-mini-fab', new: '.mat-mdc-mini-fab'},
35+
{old: '.mat-stroked-button', new: '.mat-mdc-outlined-button'},
36+
{old: '.mat-flat-button', new: '.mat-mdc-flat-button'},
37+
];
38+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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 {ButtonStylesMigrator} from './button-styles';
10+
import {StyleMigrator} from './style-migrator';
11+
12+
export const MIGRATORS: StyleMigrator[] = [new ButtonStylesMigrator()];

0 commit comments

Comments
 (0)