Skip to content

Commit 8d4b056

Browse files
authored
fix(cdk/schematics): drop tilde imports when updating to v13 (#23732)
Tilde imports have been deprecated in the Sass loader for a long time and they won't work with the new package format in v13. These changes add a migration that will drop the tilde.
1 parent 48836a8 commit 8d4b056

File tree

3 files changed

+186
-9
lines changed

3 files changed

+186
-9
lines changed

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

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,59 @@
99
import {Rule, SchematicContext} from '@angular-devkit/schematics';
1010
import {TargetVersion} from '../update-tool/target-version';
1111
import {cdkUpgradeData} from './upgrade-data';
12-
import {createMigrationSchematicRule} from './devkit-migration-rule';
12+
import {createMigrationSchematicRule, NullableDevkitMigration} from './devkit-migration-rule';
13+
import {TildeImportMigration} from './migrations/tilde-import-v13/tilde-import-migration';
14+
15+
const cdkMigrations: NullableDevkitMigration[] = [
16+
TildeImportMigration,
17+
];
1318

1419
/** Entry point for the migration schematics with target of Angular CDK 6.0.0 */
1520
export function updateToV6(): Rule {
16-
return createMigrationSchematicRule(TargetVersion.V6, [], cdkUpgradeData, onMigrationComplete);
21+
return createMigrationSchematicRule(
22+
TargetVersion.V6, cdkMigrations, cdkUpgradeData, onMigrationComplete);
1723
}
1824

1925
/** Entry point for the migration schematics with target of Angular CDK 7.0.0 */
2026
export function updateToV7(): Rule {
21-
return createMigrationSchematicRule(TargetVersion.V7, [], cdkUpgradeData, onMigrationComplete);
27+
return createMigrationSchematicRule(
28+
TargetVersion.V7, cdkMigrations, cdkUpgradeData, onMigrationComplete);
2229
}
2330

2431
/** Entry point for the migration schematics with target of Angular CDK 8.0.0 */
2532
export function updateToV8(): Rule {
26-
return createMigrationSchematicRule(TargetVersion.V8, [], cdkUpgradeData, onMigrationComplete);
33+
return createMigrationSchematicRule(
34+
TargetVersion.V8, cdkMigrations, cdkUpgradeData, onMigrationComplete);
2735
}
2836

2937
/** Entry point for the migration schematics with target of Angular CDK 9.0.0 */
3038
export function updateToV9(): Rule {
31-
return createMigrationSchematicRule(TargetVersion.V9, [], cdkUpgradeData, onMigrationComplete);
39+
return createMigrationSchematicRule(
40+
TargetVersion.V9, cdkMigrations, cdkUpgradeData, onMigrationComplete);
3241
}
3342

3443
/** Entry point for the migration schematics with target of Angular CDK 10.0.0 */
3544
export function updateToV10(): Rule {
36-
return createMigrationSchematicRule(TargetVersion.V10, [], cdkUpgradeData, onMigrationComplete);
45+
return createMigrationSchematicRule(
46+
TargetVersion.V10, cdkMigrations, cdkUpgradeData, onMigrationComplete);
3747
}
3848

3949
/** Entry point for the migration schematics with target of Angular CDK 11.0.0 */
4050
export function updateToV11(): Rule {
41-
return createMigrationSchematicRule(TargetVersion.V11, [], cdkUpgradeData, onMigrationComplete);
51+
return createMigrationSchematicRule(
52+
TargetVersion.V11, cdkMigrations, cdkUpgradeData, onMigrationComplete);
4253
}
4354

4455
/** Entry point for the migration schematics with target of Angular CDK 12.0.0 */
4556
export function updateToV12(): Rule {
46-
return createMigrationSchematicRule(TargetVersion.V12, [], cdkUpgradeData, onMigrationComplete);
57+
return createMigrationSchematicRule(
58+
TargetVersion.V12, cdkMigrations, cdkUpgradeData, onMigrationComplete);
4759
}
4860

4961
/** Entry point for the migration schematics with target of Angular CDK 13.0.0 */
5062
export function updateToV13(): Rule {
51-
return createMigrationSchematicRule(TargetVersion.V13, [], cdkUpgradeData, onMigrationComplete);
63+
return createMigrationSchematicRule(
64+
TargetVersion.V13, cdkMigrations, cdkUpgradeData, onMigrationComplete);
5265
}
5366

5467
/** Function that will be called when the migration completed. */
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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 {extname} from '@angular-devkit/core';
10+
import {ResolvedResource} from '../../../update-tool/component-resource-collector';
11+
import {TargetVersion} from '../../../update-tool/target-version';
12+
import {DevkitMigration} from '../../devkit-migration';
13+
14+
/** Migration that removes tilde symbols from imports. */
15+
export class TildeImportMigration extends DevkitMigration<null> {
16+
enabled = this.targetVersion === TargetVersion.V13;
17+
18+
override visitStylesheet(stylesheet: ResolvedResource): void {
19+
const extension = extname(stylesheet.filePath);
20+
21+
if (extension === '.scss' || extension === '.css') {
22+
const content = stylesheet.content;
23+
const migratedContent = content.replace(/@(?:import|use) +['"]~@angular\/.*['"].*;?/g,
24+
(match) => {
25+
const index = match.indexOf('~@angular');
26+
return match.slice(0, index) + match.slice(index + 1);
27+
});
28+
29+
if (migratedContent && migratedContent !== content) {
30+
this.fileSystem.edit(stylesheet.filePath)
31+
.remove(0, stylesheet.content.length)
32+
.insertLeft(0, migratedContent);
33+
}
34+
}
35+
}
36+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import {UnitTestTree} from '@angular-devkit/schematics/testing';
2+
import {createTestCaseSetup} from '../../../../testing';
3+
import {join} from 'path';
4+
import {MIGRATION_PATH} from '../../../../paths';
5+
6+
describe('v13 tilde import migration', () => {
7+
const PROJECT_PATH = '/projects/cdk-testing';
8+
const TEST_PATH = join(PROJECT_PATH, 'src/test.scss');
9+
let tree: UnitTestTree;
10+
let _writeFile: (filePath: string, text: string) => void;
11+
let runMigration: () => Promise<{logOutput: string}>;
12+
13+
beforeEach(async () => {
14+
const testSetup = await createTestCaseSetup('migration-v13', MIGRATION_PATH, []);
15+
tree = testSetup.appTree;
16+
runMigration = testSetup.runFixers;
17+
_writeFile = testSetup.writeFile;
18+
});
19+
20+
/** Writes an array of lines as a single file. */
21+
function writeLines(path: string, lines: string[]): void {
22+
_writeFile(path, lines.join('\n'));
23+
}
24+
25+
/** Reads a file and split it into an array where each item is a new line. */
26+
function splitFile(path: string): string[] {
27+
return tree.readContent(path).split('\n');
28+
}
29+
30+
it('should remove the tilde from angular imports', async () => {
31+
writeLines(TEST_PATH, [
32+
`@use '~@angular/material' as mat;`,
33+
`@import '~@angular/material/theming';`,
34+
`@import '~@angular/cdk/overlay-prebuilt.css';`,
35+
36+
`@include mat.button-theme();`,
37+
`@include mat-core();`,
38+
]);
39+
40+
await runMigration();
41+
42+
expect(splitFile(TEST_PATH)).toEqual([
43+
`@use '@angular/material' as mat;`,
44+
`@import '@angular/material/theming';`,
45+
`@import '@angular/cdk/overlay-prebuilt.css';`,
46+
47+
`@include mat.button-theme();`,
48+
`@include mat-core();`,
49+
]);
50+
});
51+
52+
it('should handle an arbitrary amount of whitespace', async () => {
53+
writeLines(TEST_PATH, [
54+
`@use '~@angular/material' as mat;`,
55+
56+
`@include mat.core();`,
57+
]);
58+
59+
await runMigration();
60+
61+
expect(splitFile(TEST_PATH)).toEqual([
62+
`@use '@angular/material' as mat;`,
63+
64+
`@include mat.core();`,
65+
]);
66+
});
67+
68+
it('should preserve tilde after the start', async () => {
69+
writeLines(TEST_PATH, [
70+
`@use '~@angular/~material' as mat;`,
71+
`@import '@angular/cdk/~overlay-prebuilt.css';`,
72+
73+
`@include mat.core();`,
74+
]);
75+
76+
await runMigration();
77+
78+
expect(splitFile(TEST_PATH)).toEqual([
79+
`@use '@angular/~material' as mat;`,
80+
`@import '@angular/cdk/~overlay-prebuilt.css';`,
81+
82+
`@include mat.core();`,
83+
]);
84+
});
85+
86+
it('should handle different types of quotes', async () => {
87+
writeLines(TEST_PATH, [
88+
`@use "~@angular/material" as mat;`,
89+
`@import '~@angular/cdk/overlay-prebuilt.css';`,
90+
91+
`@include mat.button-theme();`,
92+
`@include mat-core();`,
93+
]);
94+
95+
await runMigration();
96+
97+
expect(splitFile(TEST_PATH)).toEqual([
98+
`@use "@angular/material" as mat;`,
99+
`@import '@angular/cdk/overlay-prebuilt.css';`,
100+
101+
`@include mat.button-theme();`,
102+
`@include mat-core();`,
103+
]);
104+
});
105+
106+
it('should preserve the tilde in non-angular imports', async () => {
107+
writeLines(TEST_PATH, [
108+
`@use '~@angular-momentum/material' as mat;`,
109+
`@import '~@angular-momentum/material/theming';`,
110+
`@import '@angular/cdk/overlay-prebuilt.css';`,
111+
112+
`@include mat.button-theme();`,
113+
`@include mat-core();`,
114+
]);
115+
116+
await runMigration();
117+
118+
expect(splitFile(TEST_PATH)).toEqual([
119+
`@use '~@angular-momentum/material' as mat;`,
120+
`@import '~@angular-momentum/material/theming';`,
121+
`@import '@angular/cdk/overlay-prebuilt.css';`,
122+
123+
`@include mat.button-theme();`,
124+
`@include mat-core();`,
125+
]);
126+
});
127+
128+
});

0 commit comments

Comments
 (0)