Skip to content

Commit

Permalink
feat(material/schematics): Add Material Symbols icon font schematic
Browse files Browse the repository at this point in the history
  • Loading branch information
amysorto committed Dec 13, 2024
1 parent 0972ab6 commit 54def5a
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 7 deletions.
61 changes: 54 additions & 7 deletions src/material/schematics/ng-update/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,72 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {Rule, SchematicContext} from '@angular-devkit/schematics';
import {chain, Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
import {
appendHtmlElementToHead,
createMigrationSchematicRule,
getProjectFromWorkspace,
getProjectIndexFiles,
getWorkspaceConfigGracefully,
NullableDevkitMigration,
TargetVersion,
} from '@angular/cdk/schematics';
import {getWorkspace} from '@schematics/angular/utility/workspace';

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

const materialMigrations: NullableDevkitMigration[] = [];

/** Entry point for the migration schematics with target of Angular Material v20 */
export function updateToV20(): Rule {
return createMigrationSchematicRule(
TargetVersion.V20,
materialMigrations,
materialUpgradeData,
onMigrationComplete,
);
return chain([
createMigrationSchematicRule(
TargetVersion.V20,
materialMigrations,
materialUpgradeData,
onMigrationComplete,
),
// Updating to the new Material Symbols isn't a migration within materialMigrations since
// the index files are never visited within the migration schematic rule. The
// migrate() function within the update-tool only visits files referenced in
// typescript files which excludes the index template files:
// https://github.com/angular/components/blob/main/src/cdk/schematics/update-tool/index.ts#L71.
updateIconFontToMaterialSymbolsRule(),
]);
}

/**
* Finds the index files and adds the import for Material Symbols font if needed. As of v20,
* Material Symbols becomes the default font icon since Material Icons is deprecated. This
* rule ensures the Material Symbols font is imported for existing applications.
* @returns Rule that adds the import for the Material Symbols icon font to the index files
*/
function updateIconFontToMaterialSymbolsRule(): Rule {
return async (tree: Tree, context: SchematicContext) => {
const workspace = await getWorkspaceConfigGracefully(tree);
const projectNames = workspace!.projects.keys();

let indexFiles: string[] = [];
for (const projectName of projectNames) {
const project = getProjectFromWorkspace(await getWorkspace(tree), projectName);
indexFiles = [...indexFiles, ...getProjectIndexFiles(project)];
}

const materialSymbolsFont =
'https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined';
for (const indexFile of indexFiles) {
// Add Material Symbols font if not imported in index file. References to the deprecated
// Material Icons are not removed since some applications may have manual overrides in their
// component styles that still reference it.
if (!tree.read(indexFile)?.includes(materialSymbolsFont)) {
appendHtmlElementToHead(
tree,
indexFile,
`<link href="${materialSymbolsFont}" rel="stylesheet">`,
);
}
}
};
}

/** Function that will be called when the migration completed. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import {UnitTestTree} from '@angular-devkit/schematics/testing';
import {createTestCaseSetup} from '@angular/cdk/schematics/testing';
import {MIGRATION_PATH} from '../../paths';

const INDEX_HTML_FILE_PATH = '/projects/cdk-testing/src/index.html';

describe('v20 material symbols icon font migration', () => {
let tree: UnitTestTree;
let writeFile: (filename: string, content: string) => void;
let runMigration: () => Promise<unknown>;

function stripWhitespace(content: string): string {
return content.replace(/\s/g, '');
}

beforeEach(async () => {
const testSetup = await createTestCaseSetup('migration-v20', MIGRATION_PATH, []);
tree = testSetup.appTree;
writeFile = testSetup.writeFile;
runMigration = testSetup.runFixers;
});

it('should add Material Symbols font to index html file', async () => {
writeFile(
INDEX_HTML_FILE_PATH,
`
<!doctype html>
<html lang="en">
<head>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body></body>
</html>
`,
);

await runMigration();

expect(stripWhitespace(tree.readText(INDEX_HTML_FILE_PATH))).toBe(
stripWhitespace(`
<!doctype html>
<html lang="en">
<head>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined" rel="stylesheet">
</head>
<body></body>
</html>
`),
);
});

it('should not add Material Symbols font to index html file if it is already imported', async () => {
writeFile(
INDEX_HTML_FILE_PATH,
`
<!doctype html>
<html lang="en">
<head>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined" rel="stylesheet">
</head>
<body></body>
</html>
`,
);

await runMigration();

expect(stripWhitespace(tree.readText(INDEX_HTML_FILE_PATH))).toBe(
stripWhitespace(`
<!doctype html>
<html lang="en">
<head>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined" rel="stylesheet">
</head>
<body></body>
</html>
`),
);
});
});

0 comments on commit 54def5a

Please sign in to comment.