diff --git a/src/material/schematics/ng-generate/mdc-migration/index.ts b/src/material/schematics/ng-generate/mdc-migration/index.ts index d9a9f6da9217..456495281856 100644 --- a/src/material/schematics/ng-generate/mdc-migration/index.ts +++ b/src/material/schematics/ng-generate/mdc-migration/index.ts @@ -11,9 +11,8 @@ import {Schema} from './schema'; import {DevkitFileSystem, UpdateProject, findStylesheetFiles} from '@angular/cdk/schematics'; import {ThemingStylesMigration} from './rules/theming-styles'; import {TemplateMigration} from './rules/template-migration'; -import {MIGRATORS} from './rules'; +import {ComponentMigrator, MIGRATORS} from './rules'; import {dirname} from 'path'; -import {StyleMigrator} from './rules/style-migrator'; /** Groups of components that must be migrated together. */ const migrationGroups = [ @@ -62,7 +61,7 @@ export default function (options: Schema): Rule { console.log('Migrating:', [...componentsToMigrate]); console.log('Directory:', migrationDir); - const migrators: StyleMigrator[] = []; + const migrators: ComponentMigrator[] = []; for (let i = 0; i < MIGRATORS.length; i++) { if (componentsToMigrate.has(MIGRATORS[i].component)) { migrators.push(MIGRATORS[i]); diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/index.ts b/src/material/schematics/ng-generate/mdc-migration/rules/index.ts index e5916604b6da..82f5fd356ceb 100644 --- a/src/material/schematics/ng-generate/mdc-migration/rules/index.ts +++ b/src/material/schematics/ng-generate/mdc-migration/rules/index.ts @@ -19,18 +19,62 @@ import {SlideToggleStylesMigrator} from './components/slide-toggle/slide-toggle- import {SliderStylesMigrator} from './components/slider/slider-styles'; import {TableStylesMigrator} from './components/table/table-styles'; import {StyleMigrator} from './style-migrator'; +import {TemplateMigrator} from './template-migrator'; -export const MIGRATORS: StyleMigrator[] = [ - new ButtonStylesMigrator(), - new CardStylesMigrator(), - new CheckboxStylesMigrator(), - new ChipsStylesMigrator(), - new DialogStylesMigrator(), - new PaginatorStylesMigrator(), - new ProgressBarStylesMigrator(), - new ProgressSpinnerStylesMigrator(), - new RadioStylesMigrator(), - new SlideToggleStylesMigrator(), - new SliderStylesMigrator(), - new TableStylesMigrator(), +/** Contains the migrators to migrate a single component. */ +export interface ComponentMigrator { + component: string; + styles: StyleMigrator; + template?: TemplateMigrator; +} + +export const MIGRATORS: ComponentMigrator[] = [ + { + component: 'button', + styles: new ButtonStylesMigrator(), + }, + { + component: 'card', + styles: new CardStylesMigrator(), + }, + { + component: 'checkbox', + styles: new CheckboxStylesMigrator(), + }, + { + component: 'chips', + styles: new ChipsStylesMigrator(), + }, + { + component: 'dialog', + styles: new DialogStylesMigrator(), + }, + { + component: 'paginator', + styles: new PaginatorStylesMigrator(), + }, + { + component: 'progress-bar', + styles: new ProgressBarStylesMigrator(), + }, + { + component: 'progress-spinner', + styles: new ProgressSpinnerStylesMigrator(), + }, + { + component: 'radio', + styles: new RadioStylesMigrator(), + }, + { + component: 'slide-toggle', + styles: new SlideToggleStylesMigrator(), + }, + { + component: 'slider', + styles: new SliderStylesMigrator(), + }, + { + component: 'table', + styles: new TableStylesMigrator(), + }, ]; diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/template-migration.ts b/src/material/schematics/ng-generate/mdc-migration/rules/template-migration.ts index 83f7971804f3..d5598fda0e0a 100644 --- a/src/material/schematics/ng-generate/mdc-migration/rules/template-migration.ts +++ b/src/material/schematics/ng-generate/mdc-migration/rules/template-migration.ts @@ -8,10 +8,10 @@ import {Migration, ResolvedResource} from '@angular/cdk/schematics'; import {SchematicContext} from '@angular-devkit/schematics'; -import {StyleMigrator} from './style-migrator'; import {visitElements, parseTemplate} from './tree-traversal'; +import {ComponentMigrator} from '.'; -export class TemplateMigration extends Migration { +export class TemplateMigration extends Migration { enabled = true; override visitTemplate(template: ResolvedResource) { diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/template-migrator.ts b/src/material/schematics/ng-generate/mdc-migration/rules/template-migrator.ts new file mode 100644 index 000000000000..0ab5641a1ed9 --- /dev/null +++ b/src/material/schematics/ng-generate/mdc-migration/rules/template-migrator.ts @@ -0,0 +1,39 @@ +/** + * @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 * as compiler from '@angular/compiler'; + +export abstract class TemplateMigrator { + /** The name of the component that this migration handles. */ + abstract component: string; + + /** The tag name to be updated in the template. */ + abstract tagName: string; + + /** + * Updates the start tag of the given node in the html template. + * + * @param template The html content to be updated. + * @param node The Element node to be updated. + * @returns The updated template. + */ + updateEndTag(template: string, node: compiler.TmplAstElement): string { + return template; + } + + /** + * Updates the end tag of the given node in the html template. + * + * @param template The html content to be updated. + * @param node The Element node to be updated. + * @returns The updated template. + */ + updateStartTag(template: string, node: compiler.TmplAstElement): string { + return template; + } +} diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/theming-styles.ts b/src/material/schematics/ng-generate/mdc-migration/rules/theming-styles.ts index 6862b0351898..6b74cc3b5f8f 100644 --- a/src/material/schematics/ng-generate/mdc-migration/rules/theming-styles.ts +++ b/src/material/schematics/ng-generate/mdc-migration/rules/theming-styles.ts @@ -8,11 +8,11 @@ import {Migration, ResolvedResource} from '@angular/cdk/schematics'; import {SchematicContext} from '@angular-devkit/schematics'; -import {StyleMigrator} from './style-migrator'; import * as postcss from 'postcss'; import * as scss from 'postcss-scss'; +import {ComponentMigrator} from '.'; -export class ThemingStylesMigration extends Migration { +export class ThemingStylesMigration extends Migration { enabled = true; namespace: string; @@ -40,13 +40,13 @@ export class ThemingStylesMigration extends Migration { - return m.isLegacyMixin(this.namespace, atRule); + return m.styles.isLegacyMixin(this.namespace, atRule); }); if (migrator) { - migrator.replaceMixin(this.namespace, atRule); + migrator.styles.replaceMixin(this.namespace, atRule); } else if (atRule.params.includes('all-component-themes') && atRule.parent) { this.upgradeData.forEach(m => { - m?.addNewMixinsAfterNode(this.namespace, atRule); + m?.styles.addNewMixinsAfterNode(this.namespace, atRule); }); } } @@ -56,15 +56,15 @@ export class ThemingStylesMigration extends Migration { - isLegacySelector = m.isLegacySelector(rule); - isDeprecatedSelector = m.isDeprecatedSelector(rule); + isLegacySelector = m.styles.isLegacySelector(rule); + isDeprecatedSelector = m.styles.isDeprecatedSelector(rule); return isLegacySelector || isDeprecatedSelector; }); if (isLegacySelector) { - migrator?.replaceLegacySelector(rule); + migrator?.styles.replaceLegacySelector(rule); } else if (isDeprecatedSelector) { - migrator?.addDeprecatedSelectorComment(rule); + migrator?.styles.addDeprecatedSelectorComment(rule); } } } diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.spec.ts b/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.spec.ts index af894e78854d..ac5df291f9f3 100644 --- a/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.spec.ts +++ b/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.spec.ts @@ -109,5 +109,14 @@ describe('#visitElements', () => { '', ); }); + + it('should handle adding multiple attrs to a single element', async () => { + let html = ''; + visitElements(parseTemplate(html).nodes, undefined, node => { + html = addAttribute(html, node, 'attr1', 'val1'); + html = addAttribute(html, node, 'attr2', 'val2'); + }); + expect(html).toBe(''); + }); }); });