From 587b9f46a3ebe276ffee1b88299108bce6934065 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sun, 18 Apr 2021 12:16:37 +0200 Subject: [PATCH] fix(material/schematics): replace removed variables with their values in sass api migration The new Sass API removes some variables that had been previously exported by accident. These changes expand the migration so that usages of those variables are replaced with the values. The replacement doesn't cover variable assignments, because migrating them is impossible. --- .../ng-generate/theming-api/config.ts | 187 ++++++++++++++++++ .../ng-generate/theming-api/index.spec.ts | 65 ++++++ .../ng-generate/theming-api/migration.ts | 114 +++-------- 3 files changed, 277 insertions(+), 89 deletions(-) create mode 100644 src/material/schematics/ng-generate/theming-api/config.ts diff --git a/src/material/schematics/ng-generate/theming-api/config.ts b/src/material/schematics/ng-generate/theming-api/config.ts new file mode 100644 index 000000000000..b13b2414632a --- /dev/null +++ b/src/material/schematics/ng-generate/theming-api/config.ts @@ -0,0 +1,187 @@ +/** + * @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 + */ + +/** Mapping of Material mixins that should be renamed. */ +export const materialMixins: Record = { + 'mat-core': 'core', + 'mat-core-color': 'core-color', + 'mat-core-theme': 'core-theme', + 'angular-material-theme': 'all-component-themes', + 'angular-material-typography': 'all-component-typographies', + 'angular-material-color': 'all-component-colors', + 'mat-base-typography': 'typography-hierarchy', + 'mat-typography-level-to-styles': 'typography-level', + 'mat-elevation': 'elevation', + 'mat-overridable-elevation': 'overridable-elevation', + 'mat-elevation-transition': 'elevation-transition', + 'mat-ripple': 'ripple', + 'mat-ripple-color': 'ripple-color', + 'mat-ripple-theme': 'ripple-theme', + 'mat-strong-focus-indicators': 'strong-focus-indicators', + 'mat-strong-focus-indicators-color': 'strong-focus-indicators-color', + 'mat-strong-focus-indicators-theme': 'strong-focus-indicators-theme', + 'mat-font-shorthand': 'font-shorthand', + // The expansion panel is a special case, because the package is called `expansion`, but the + // mixins were prefixed with `expansion-panel`. This was corrected by the Sass module migration. + 'mat-expansion-panel-theme': 'expansion-theme', + 'mat-expansion-panel-color': 'expansion-color', + 'mat-expansion-panel-typography': 'expansion-typography', +}; + +// The component themes all follow the same pattern so we can spare ourselves some typing. +[ + 'option', 'optgroup', 'pseudo-checkbox', 'autocomplete', 'badge', 'bottom-sheet', 'button', + 'button-toggle', 'card', 'checkbox', 'chips', 'divider', 'table', 'datepicker', 'dialog', + 'grid-list', 'icon', 'input', 'list', 'menu', 'paginator', 'progress-bar', 'progress-spinner', + 'radio', 'select', 'sidenav', 'slide-toggle', 'slider', 'stepper', 'sort', 'tabs', 'toolbar', + 'tooltip', 'snack-bar', 'form-field', 'tree' +].forEach(name => { + materialMixins[`mat-${name}-theme`] = `${name}-theme`; + materialMixins[`mat-${name}-color`] = `${name}-color`; + materialMixins[`mat-${name}-typography`] = `${name}-typography`; +}); + +/** Mapping of Material functions that should be renamed. */ +export const materialFunctions: Record = { + 'mat-color': 'get-color-from-palette', + 'mat-contrast': 'get-contrast-color-from-palette', + 'mat-palette': 'define-palette', + 'mat-dark-theme': 'define-dark-theme', + 'mat-light-theme': 'define-light-theme', + 'mat-typography-level': 'define-typography-level', + 'mat-typography-config': 'define-typography-config', + 'mat-font-size': 'font-size', + 'mat-line-height': 'line-height', + 'mat-font-weight': 'font-weight', + 'mat-letter-spacing': 'letter-spacing', + 'mat-font-family': 'font-family', +}; + +/** Mapping of Material variables that should be renamed. */ +export const materialVariables: Record = { + 'mat-light-theme-background': 'light-theme-background-palette', + 'mat-dark-theme-background': 'dark-theme-background-palette', + 'mat-light-theme-foreground': 'light-theme-foreground-palette', + 'mat-dark-theme-foreground': 'dark-theme-foreground-palette', +}; + +// The palettes all follow the same pattern. +[ + 'red', 'pink', 'indigo', 'purple', 'deep-purple', 'blue', 'light-blue', 'cyan', 'teal', 'green', + 'light-green', 'lime', 'yellow', 'amber', 'orange', 'deep-orange', 'brown', 'grey', 'gray', + 'blue-grey', 'blue-gray' +].forEach(name => materialVariables[`mat-${name}`] = `${name}-palette`); + +/** Mapping of CDK variables that should be renamed. */ +export const cdkVariables: Record = { + 'cdk-z-index-overlay-container': 'overlay-container-z-index', + 'cdk-z-index-overlay': 'overlay-z-index', + 'cdk-z-index-overlay-backdrop': 'overlay-backdrop-z-index', + 'cdk-overlay-dark-backdrop-background': 'overlay-backdrop-color', +}; + +/** Mapping of CDK mixins that should be renamed. */ +export const cdkMixins: Record = { + 'cdk-overlay': 'overlay', + 'cdk-a11y': 'a11y-visually-hidden', + 'cdk-high-contrast': 'high-contrast', + 'cdk-text-field-autofill-color': 'text-field-autofill-color', + // This one was split up into two mixins which is trickier to + // migrate so for now we forward to the deprecated variant. + 'cdk-text-field': 'text-field', +}; + +/** + * Material variables that have been removed from the public API + * and which should be replaced with their values. + */ +export const removedMaterialVariables: Record = { + // Note: there's also a usage of a variable called `$pi`, but the name is short enough that + // it matches things like `$mat-pink`. Don't migrate it since it's unlikely to be used. + 'mat-xsmall': `'max-width: 599px'`, + 'mat-small': `'max-width: 959px'`, + 'mat-toggle-padding': '8px', + 'mat-toggle-size': '20px', + 'mat-linear-out-slow-in-timing-function': 'cubic-bezier(0, 0, 0.2, 0.1)', + 'mat-fast-out-slow-in-timing-function': 'cubic-bezier(0.4, 0, 0.2, 1)', + 'mat-fast-out-linear-in-timing-function': 'cubic-bezier(0.4, 0, 1, 1)', + 'mat-elevation-transition-duration': '280ms', + 'mat-elevation-transition-timing-function': 'cubic-bezier(0.4, 0, 0.2, 1)', + 'mat-elevation-color': '#000', + 'mat-elevation-opacity': '1', + 'mat-elevation-prefix': `'mat-elevation-z'`, + 'mat-ripple-color-opacity': '0.1', + 'mat-badge-font-size': '12px', + 'mat-badge-font-weight': '600', + 'mat-badge-default-size': '22px', + 'mat-badge-small-size': '16px', + 'mat-badge-large-size': '28px', + 'mat-button-toggle-standard-height': '48px', + 'mat-button-toggle-standard-minimum-height': '24px', + 'mat-button-toggle-standard-maximum-height': '48px', + 'mat-chip-remove-font-size': '18px', + 'mat-datepicker-selected-today-box-shadow-width': '1px', + 'mat-datepicker-selected-fade-amount': '0.6', + 'mat-datepicker-range-fade-amount': '0.2', + 'mat-datepicker-today-fade-amount': '0.2', + 'mat-calendar-body-font-size': '13px', + 'mat-calendar-weekday-table-font-size': '11px', + 'mat-expansion-panel-header-collapsed-height': '48px', + 'mat-expansion-panel-header-collapsed-minimum-height': '36px', + 'mat-expansion-panel-header-collapsed-maximum-height': '48px', + 'mat-expansion-panel-header-expanded-height': '64px', + 'mat-expansion-panel-header-expanded-minimum-height': '48px', + 'mat-expansion-panel-header-expanded-maximum-height': '64px', + 'mat-expansion-panel-header-transition': '225ms cubic-bezier(0.4, 0, 0.2, 1)', + 'mat-paginator-height': '56px', + 'mat-paginator-minimum-height': '40px', + 'mat-paginator-maximum-height': '56px', + 'mat-stepper-header-height': '72px', + 'mat-stepper-header-minimum-height': '42px', + 'mat-stepper-header-maximum-height': '72px', + 'mat-stepper-label-header-height': '24px', + 'mat-stepper-label-position-bottom-top-gap': '16px', + 'mat-stepper-label-min-width': '50px', + 'mat-vertical-stepper-content-margin': '36px', + 'mat-stepper-side-gap': '24px', + 'mat-stepper-line-width': '1px', + 'mat-stepper-line-gap': '8px', + 'mat-step-sub-label-font-size': '12px', + 'mat-step-header-icon-size': '16px', + 'mat-toolbar-minimum-height': '44px', + 'mat-toolbar-height-desktop': '64px', + 'mat-toolbar-maximum-height-desktop': '64px', + 'mat-toolbar-minimum-height-desktop': '44px', + 'mat-toolbar-height-mobile': '56px', + 'mat-toolbar-maximum-height-mobile': '56px', + 'mat-toolbar-minimum-height-mobile': '44px', + 'mat-tooltip-target-height': '22px', + 'mat-tooltip-font-size': '10px', + 'mat-tooltip-vertical-padding': '6px', + 'mat-tooltip-handset-target-height': '30px', + 'mat-tooltip-handset-font-size': '14px', + 'mat-tooltip-handset-vertical-padding': '8px', + 'mat-tree-node-height': '48px', + 'mat-tree-node-minimum-height': '24px', + 'mat-tree-node-maximum-height': '48px', + 'z-index-fab': '20', + 'z-index-drawer': '100', + 'ease-in-out-curve-function': 'cubic-bezier(0.35, 0, 0.25, 1)', + 'swift-ease-out-duration': '400ms', + 'swift-ease-out-timing-function': 'cubic-bezier(0.25, 0.8, 0.25, 1)', + 'swift-ease-out': 'all 400ms cubic-bezier(0.25, 0.8, 0.25, 1)', + 'swift-ease-in-duration': '300ms', + 'swift-ease-in-timing-function': 'cubic-bezier(0.55, 0, 0.55, 0.2)', + 'swift-ease-in': 'all 300ms cubic-bezier(0.55, 0, 0.55, 0.2)', + 'swift-ease-in-out-duration': '500ms', + 'swift-ease-in-out-timing-function': 'cubic-bezier(0.35, 0, 0.25, 1)', + 'swift-ease-in-out': 'all 500ms cubic-bezier(0.35, 0, 0.25, 1)', + 'swift-linear-duration': '80ms', + 'swift-linear-timing-function': 'linear', + 'swift-linear': 'all 80ms linear' +}; diff --git a/src/material/schematics/ng-generate/theming-api/index.spec.ts b/src/material/schematics/ng-generate/theming-api/index.spec.ts index 89573d708095..56ce8288ef87 100644 --- a/src/material/schematics/ng-generate/theming-api/index.spec.ts +++ b/src/material/schematics/ng-generate/theming-api/index.spec.ts @@ -505,5 +505,70 @@ describe('Material theming API schematic', () => { ]); }); + it('should replace removed variables with their values', async () => { + const app = await createTestApp(runner); + app.create('/theme.scss', [ + `@import '~@angular/material/theming';`, + ``, + `@include mat-button-toggle-theme();`, + ``, + + `.my-button-toggle {`, + `height: $mat-button-toggle-standard-height + 10px;`, + `transition: $swift-ease-out;`, + `}`, + ``, + `@media ($mat-small) {`, + `.my-button-toggle {`, + `height: $mat-button-toggle-standard-minimum-height;`, + `}`, + `}` + ].join('\n')); + + const tree = await runner.runSchematicAsync('theming-api', options, app).toPromise(); + expect(getFileContent(tree, '/theme.scss').split('\n')).toEqual([ + `@use '~@angular/material' as mat;`, + ``, + `@include mat.button-toggle-theme();`, + ``, + + `.my-button-toggle {`, + `height: 48px + 10px;`, + `transition: all 400ms cubic-bezier(0.25, 0.8, 0.25, 1);`, + `}`, + ``, + `@media ('max-width: 959px') {`, + `.my-button-toggle {`, + `height: 24px;`, + `}`, + `}` + ]); + }); + + it('should not replace assignments to removed variables', async () => { + const app = await createTestApp(runner); + app.create('/theme.scss', [ + `@import '~@angular/material/theming';`, + ``, + `$mat-button-toggle-standard-height: 50px;`, + `$mat-button-toggle-standard-minimum-height : 12px;`, + `$mat-toggle-padding:10px;`, + `$mat-toggle-size: 11px;`, + ``, + `@include mat-button-toggle-theme();`, + ].join('\n')); + + const tree = await runner.runSchematicAsync('theming-api', options, app).toPromise(); + expect(getFileContent(tree, '/theme.scss').split('\n')).toEqual([ + `@use '~@angular/material' as mat;`, + ``, + `$mat-button-toggle-standard-height: 50px;`, + `$mat-button-toggle-standard-minimum-height : 12px;`, + `$mat-toggle-padding:10px;`, + `$mat-toggle-size: 11px;`, + ``, + `@include mat.button-toggle-theme();`, + ]); + }); }); diff --git a/src/material/schematics/ng-generate/theming-api/migration.ts b/src/material/schematics/ng-generate/theming-api/migration.ts index 503f35741cac..a46734677ca3 100644 --- a/src/material/schematics/ng-generate/theming-api/migration.ts +++ b/src/material/schematics/ng-generate/theming-api/migration.ts @@ -6,95 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -/** Mapping of Material mixins that should be renamed. */ -const materialMixins: Record = { - 'mat-core': 'core', - 'mat-core-color': 'core-color', - 'mat-core-theme': 'core-theme', - 'angular-material-theme': 'all-component-themes', - 'angular-material-typography': 'all-component-typographies', - 'angular-material-color': 'all-component-colors', - 'mat-base-typography': 'typography-hierarchy', - 'mat-typography-level-to-styles': 'typography-level', - 'mat-elevation': 'elevation', - 'mat-overridable-elevation': 'overridable-elevation', - 'mat-elevation-transition': 'elevation-transition', - 'mat-ripple': 'ripple', - 'mat-ripple-color': 'ripple-color', - 'mat-ripple-theme': 'ripple-theme', - 'mat-strong-focus-indicators': 'strong-focus-indicators', - 'mat-strong-focus-indicators-color': 'strong-focus-indicators-color', - 'mat-strong-focus-indicators-theme': 'strong-focus-indicators-theme', - 'mat-font-shorthand': 'font-shorthand', - // The expansion panel is a special case, because the package is called `expansion`, but the - // mixins were prefixed with `expansion-panel`. This was corrected by the Sass module migration. - 'mat-expansion-panel-theme': 'expansion-theme', - 'mat-expansion-panel-color': 'expansion-color', - 'mat-expansion-panel-typography': 'expansion-typography', -}; - -// The component themes all follow the same pattern so we can spare ourselves some typing. -[ - 'option', 'optgroup', 'pseudo-checkbox', 'autocomplete', 'badge', 'bottom-sheet', 'button', - 'button-toggle', 'card', 'checkbox', 'chips', 'divider', 'table', 'datepicker', 'dialog', - 'grid-list', 'icon', 'input', 'list', 'menu', 'paginator', 'progress-bar', 'progress-spinner', - 'radio', 'select', 'sidenav', 'slide-toggle', 'slider', 'stepper', 'sort', 'tabs', 'toolbar', - 'tooltip', 'snack-bar', 'form-field', 'tree' -].forEach(name => { - materialMixins[`mat-${name}-theme`] = `${name}-theme`; - materialMixins[`mat-${name}-color`] = `${name}-color`; - materialMixins[`mat-${name}-typography`] = `${name}-typography`; -}); - -/** Mapping of Material functions that should be renamed. */ -const materialFunctions: Record = { - 'mat-color': 'get-color-from-palette', - 'mat-contrast': 'get-contrast-color-from-palette', - 'mat-palette': 'define-palette', - 'mat-dark-theme': 'define-dark-theme', - 'mat-light-theme': 'define-light-theme', - 'mat-typography-level': 'define-typography-level', - 'mat-typography-config': 'define-typography-config', - 'mat-font-size': 'font-size', - 'mat-line-height': 'line-height', - 'mat-font-weight': 'font-weight', - 'mat-letter-spacing': 'letter-spacing', - 'mat-font-family': 'font-family', -}; - -/** Mapping of Material variables that should be renamed. */ -const materialVariables: Record = { - 'mat-light-theme-background': 'light-theme-background-palette', - 'mat-dark-theme-background': 'dark-theme-background-palette', - 'mat-light-theme-foreground': 'light-theme-foreground-palette', - 'mat-dark-theme-foreground': 'dark-theme-foreground-palette', -}; - -// The palettes all follow the same pattern. -[ - 'red', 'pink', 'indigo', 'purple', 'deep-purple', 'blue', 'light-blue', 'cyan', 'teal', 'green', - 'light-green', 'lime', 'yellow', 'amber', 'orange', 'deep-orange', 'brown', 'grey', 'gray', - 'blue-grey', 'blue-gray' -].forEach(name => materialVariables[`mat-${name}`] = `${name}-palette`); - -/** Mapping of CDK variables that should be renamed. */ -const cdkVariables: Record = { - 'cdk-z-index-overlay-container': 'overlay-container-z-index', - 'cdk-z-index-overlay': 'overlay-z-index', - 'cdk-z-index-overlay-backdrop': 'overlay-backdrop-z-index', - 'cdk-overlay-dark-backdrop-background': 'overlay-backdrop-color', -}; - -/** Mapping of CDK mixins that should be renamed. */ -const cdkMixins: Record = { - 'cdk-overlay': 'overlay', - 'cdk-a11y': 'a11y-visually-hidden', - 'cdk-high-contrast': 'high-contrast', - 'cdk-text-field-autofill-color': 'text-field-autofill-color', - // This one was split up into two mixins which is trickier to - // migrate so for now we forward to the deprecated variant. - 'cdk-text-field': 'text-field', -}; +import { + materialMixins, + materialFunctions, + materialVariables, + cdkMixins, + cdkVariables, + removedMaterialVariables +} from './config'; /** * Migrates the content of a file to the new theming API. Note that this migration is using plain @@ -129,6 +48,7 @@ export function migrateFileContent(content: string, content = removeStrings(content, materialResults.imports); content = removeStrings(content, cdkResults.imports); content = content.replace(/^\s+/, ''); + content = replaceRemovedVariables(content, removedMaterialVariables); } } @@ -346,3 +266,19 @@ function extractNamespaceFromUseStatement(fullImport: string): string { throw Error(`Could not extract namespace from import "${fullImport}".`); } + +/** + * Replaces variables that have been removed with their values. + * @param content Content of the file to be migrated. + * @param variables Mapping between variable names and their values. + */ +function replaceRemovedVariables(content: string, variables: Record): string { + Object.keys(variables).sort(sortLengthDescending).forEach(variableName => { + // Note that the pattern uses a negative lookahead to exclude + // variable assignments, because they can't be migrated. + const regex = new RegExp(`\\$${escapeRegExp(variableName)}(?!\\s+:|:)`, 'g'); + content = content.replace(regex, variables[variableName]); + }); + + return content; +}