refactor(schematics): split up upgrade data for target version (#12951)

This commit is contained in:
Paul Gschwendtner
2018-09-04 20:54:08 +02:00
committed by Jeremy Elbourn
parent da95e34ef6
commit cfb4f58eda
28 changed files with 985 additions and 880 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ import {createUpdateRule} from './update';
/** Possible versions that can be automatically migrated by `ng update`. */
export enum TargetVersion {
V6,
V7
V7,
}
/** Entry point for the migration schematics with target of Angular Material 6.0.0 */
@@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {transformChanges} from '../transform-change-data';
import {VersionChanges} from '../transform-change-data';
import {TargetVersion} from '../../index';
export interface MaterialAttributeSelectorData {
/** The attribute name to replace. */
@@ -15,18 +16,20 @@ export interface MaterialAttributeSelectorData {
replaceWith: string;
}
export const attributeSelectors = transformChanges<MaterialAttributeSelectorData>([
{
pr: 'https://github.com/angular/material2/pull/10257',
changes: [
{
replace: 'cdkPortalHost',
replaceWith: 'cdkPortalOutlet'
},
{
replace: 'portalHost',
replaceWith: 'cdkPortalOutlet'
}
]
}
]);
export const attributeSelectors: VersionChanges<MaterialAttributeSelectorData> = {
[TargetVersion.V6]: [
{
pr: 'https://github.com/angular/material2/pull/10257',
changes: [
{
replace: 'cdkPortalHost',
replaceWith: 'cdkPortalOutlet'
},
{
replace: 'portalHost',
replaceWith: 'cdkPortalOutlet'
}
]
}
]
};
@@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {transformChanges} from '../transform-change-data';
import {TargetVersion} from '../../index';
import {VersionChanges} from '../transform-change-data';
export interface MaterialClassNameData {
/** The Class name to replace. */
@@ -15,56 +16,58 @@ export interface MaterialClassNameData {
replaceWith: string;
}
export const classNames = transformChanges<MaterialClassNameData>([
{
pr: 'https://github.com/angular/material2/pull/10161',
changes: [
{
replace: 'ConnectedOverlayDirective',
replaceWith: 'CdkConnectedOverlay'
},
{
replace: 'OverlayOrigin',
replaceWith: 'CdkOverlayOrigin'
}
]
},
export const classNames: VersionChanges<MaterialClassNameData> = {
[TargetVersion.V6]: [
{
pr: 'https://github.com/angular/material2/pull/10161',
changes: [
{
replace: 'ConnectedOverlayDirective',
replaceWith: 'CdkConnectedOverlay'
},
{
replace: 'OverlayOrigin',
replaceWith: 'CdkOverlayOrigin'
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10267',
changes: [
{
replace: 'ObserveContent',
replaceWith: 'CdkObserveContent'
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10267',
changes: [
{
replace: 'ObserveContent',
replaceWith: 'CdkObserveContent'
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10291',
changes: [
{
replace: 'FloatPlaceholderType',
replaceWith: 'FloatLabelType'
},
{
replace: 'MAT_PLACEHOLDER_GLOBAL_OPTIONS',
replaceWith: 'MAT_LABEL_GLOBAL_OPTIONS'
},
{
replace: 'PlaceholderOptions',
replaceWith: 'LabelOptions'
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10291',
changes: [
{
replace: 'FloatPlaceholderType',
replaceWith: 'FloatLabelType'
},
{
replace: 'MAT_PLACEHOLDER_GLOBAL_OPTIONS',
replaceWith: 'MAT_LABEL_GLOBAL_OPTIONS'
},
{
replace: 'PlaceholderOptions',
replaceWith: 'LabelOptions'
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10325',
changes: [
{
replace: 'FocusTrapDirective',
replaceWith: 'CdkTrapFocus'
}
]
}
]);
{
pr: 'https://github.com/angular/material2/pull/10325',
changes: [
{
replace: 'FocusTrapDirective',
replaceWith: 'CdkTrapFocus'
}
]
}
]
};
@@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {transformChanges} from '../transform-change-data';
import {TargetVersion} from '../../index';
import {VersionChanges} from '../transform-change-data';
export interface MaterialCssSelectorData {
/** The CSS selector to replace. */
@@ -24,84 +25,87 @@ export interface MaterialCssSelectorData {
};
}
export const cssSelectors = transformChanges<MaterialCssSelectorData>([
{
pr: 'https://github.com/angular/material2/pull/10296',
changes: [
{
replace: '.mat-form-field-placeholder',
replaceWith: '.mat-form-field-label'
},
{
replace: '.mat-input-container',
replaceWith: '.mat-form-field'
},
{
replace: '.mat-input-flex',
replaceWith: '.mat-form-field-flex'
},
{
replace: '.mat-input-hint-spacer',
replaceWith: '.mat-form-field-hint-spacer'
},
{
replace: '.mat-input-hint-wrapper',
replaceWith: '.mat-form-field-hint-wrapper'
},
{
replace: '.mat-input-infix',
replaceWith: '.mat-form-field-infix'
},
{
replace: '.mat-input-invalid',
replaceWith: '.mat-form-field-invalid'
},
{
replace: '.mat-input-placeholder',
replaceWith: '.mat-form-field-label'
},
{
replace: '.mat-input-placeholder-wrapper',
replaceWith: '.mat-form-field-label-wrapper'
},
{
replace: '.mat-input-prefix',
replaceWith: '.mat-form-field-prefix'
},
{
replace: '.mat-input-ripple',
replaceWith: '.mat-form-field-ripple'
},
{
replace: '.mat-input-subscript-wrapper',
replaceWith: '.mat-form-field-subscript-wrapper'
},
{
replace: '.mat-input-suffix',
replaceWith: '.mat-form-field-suffix'
},
{
replace: '.mat-input-underline',
replaceWith: '.mat-form-field-underline'
},
{
replace: '.mat-input-wrapper',
replaceWith: '.mat-form-field-wrapper'
}
]
},
// TODO(devversion): this shouldn't be here because it's not a CSS selector. Move into misc rule.
{
pr: 'https://github.com/angular/material2/pull/10430',
changes: [
{
replace: '$mat-font-family',
replaceWith: "Roboto, 'Helvetica Neue', sans-serif",
whitelist: {
stylesheet: true
export const cssSelectors: VersionChanges<MaterialCssSelectorData> = {
[TargetVersion.V6]: [
{
pr: 'https://github.com/angular/material2/pull/10296',
changes: [
{
replace: '.mat-form-field-placeholder',
replaceWith: '.mat-form-field-label'
},
{
replace: '.mat-input-container',
replaceWith: '.mat-form-field'
},
{
replace: '.mat-input-flex',
replaceWith: '.mat-form-field-flex'
},
{
replace: '.mat-input-hint-spacer',
replaceWith: '.mat-form-field-hint-spacer'
},
{
replace: '.mat-input-hint-wrapper',
replaceWith: '.mat-form-field-hint-wrapper'
},
{
replace: '.mat-input-infix',
replaceWith: '.mat-form-field-infix'
},
{
replace: '.mat-input-invalid',
replaceWith: '.mat-form-field-invalid'
},
{
replace: '.mat-input-placeholder',
replaceWith: '.mat-form-field-label'
},
{
replace: '.mat-input-placeholder-wrapper',
replaceWith: '.mat-form-field-label-wrapper'
},
{
replace: '.mat-input-prefix',
replaceWith: '.mat-form-field-prefix'
},
{
replace: '.mat-input-ripple',
replaceWith: '.mat-form-field-ripple'
},
{
replace: '.mat-input-subscript-wrapper',
replaceWith: '.mat-form-field-subscript-wrapper'
},
{
replace: '.mat-input-suffix',
replaceWith: '.mat-form-field-suffix'
},
{
replace: '.mat-input-underline',
replaceWith: '.mat-form-field-underline'
},
{
replace: '.mat-input-wrapper',
replaceWith: '.mat-form-field-wrapper'
}
}
]
}
]);
]
},
// TODO(devversion): this shouldn't be here because it's not a CSS selector. Move into misc
// rule.
{
pr: 'https://github.com/angular/material2/pull/10430',
changes: [
{
replace: '$mat-font-family',
replaceWith: "Roboto, 'Helvetica Neue', sans-serif",
whitelist: {
stylesheet: true
}
}
]
}
]
};
@@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {transformChanges} from '../transform-change-data';
import {TargetVersion} from '../../index';
import {VersionChanges} from '../transform-change-data';
export interface MaterialElementSelectorData {
/** The element name to replace. */
@@ -15,14 +16,16 @@ export interface MaterialElementSelectorData {
replaceWith: string;
}
export const elementSelectors = transformChanges<MaterialElementSelectorData>([
{
pr: 'https://github.com/angular/material2/pull/10297',
changes: [
{
replace: 'mat-input-container',
replaceWith: 'mat-form-field'
}
]
}
]);
export const elementSelectors: VersionChanges<MaterialElementSelectorData> = {
[TargetVersion.V6]: [
{
pr: 'https://github.com/angular/material2/pull/10297',
changes: [
{
replace: 'mat-input-container',
replaceWith: 'mat-form-field'
}
]
}
]
};
@@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {transformChanges} from '../transform-change-data';
import {TargetVersion} from '../../index';
import {VersionChanges} from '../transform-change-data';
export interface MaterialInputNameData {
/** The @Input() name to replace. */
@@ -28,199 +29,201 @@ export interface MaterialInputNameData {
};
}
export const inputNames = transformChanges<MaterialInputNameData>([
{
pr: 'https://github.com/angular/material2/pull/10161',
changes: [
{
replace: 'origin',
replaceWith: 'cdkConnectedOverlayOrigin',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
export const inputNames: VersionChanges<MaterialInputNameData> = {
[TargetVersion.V6]: [
{
pr: 'https://github.com/angular/material2/pull/10161',
changes: [
{
replace: 'origin',
replaceWith: 'cdkConnectedOverlayOrigin',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'positions',
replaceWith: 'cdkConnectedOverlayPositions',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'offsetX',
replaceWith: 'cdkConnectedOverlayOffsetX',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'offsetY',
replaceWith: 'cdkConnectedOverlayOffsetY',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'width',
replaceWith: 'cdkConnectedOverlayWidth',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'height',
replaceWith: 'cdkConnectedOverlayHeight',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'minWidth',
replaceWith: 'cdkConnectedOverlayMinWidth',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'minHeight',
replaceWith: 'cdkConnectedOverlayMinHeight',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'backdropClass',
replaceWith: 'cdkConnectedOverlayBackdropClass',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'scrollStrategy',
replaceWith: 'cdkConnectedOverlayScrollStrategy',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'open',
replaceWith: 'cdkConnectedOverlayOpen',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'hasBackdrop',
replaceWith: 'cdkConnectedOverlayHasBackdrop',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
}
},
{
replace: 'positions',
replaceWith: 'cdkConnectedOverlayPositions',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'offsetX',
replaceWith: 'cdkConnectedOverlayOffsetX',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'offsetY',
replaceWith: 'cdkConnectedOverlayOffsetY',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'width',
replaceWith: 'cdkConnectedOverlayWidth',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'height',
replaceWith: 'cdkConnectedOverlayHeight',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'minWidth',
replaceWith: 'cdkConnectedOverlayMinWidth',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'minHeight',
replaceWith: 'cdkConnectedOverlayMinHeight',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'backdropClass',
replaceWith: 'cdkConnectedOverlayBackdropClass',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'scrollStrategy',
replaceWith: 'cdkConnectedOverlayScrollStrategy',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'open',
replaceWith: 'cdkConnectedOverlayOpen',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
},
{
replace: 'hasBackdrop',
replaceWith: 'cdkConnectedOverlayHasBackdrop',
whitelist: {
attributes: ['cdk-connected-overlay', 'connected-overlay', 'cdkConnectedOverlay']
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10218',
changes: [
{
replace: 'align',
replaceWith: 'labelPosition',
whitelist: {
elements: ['mat-radio-group', 'mat-radio-button']
{
pr: 'https://github.com/angular/material2/pull/10218',
changes: [
{
replace: 'align',
replaceWith: 'labelPosition',
whitelist: {
elements: ['mat-radio-group', 'mat-radio-button']
}
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10279',
changes: [
{
replace: 'align',
replaceWith: 'position',
whitelist: {
elements: ['mat-drawer', 'mat-sidenav']
{
pr: 'https://github.com/angular/material2/pull/10279',
changes: [
{
replace: 'align',
replaceWith: 'position',
whitelist: {
elements: ['mat-drawer', 'mat-sidenav']
}
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10294',
changes: [
{
replace: 'dividerColor',
replaceWith: 'color',
whitelist: {
elements: ['mat-form-field']
{
pr: 'https://github.com/angular/material2/pull/10294',
changes: [
{
replace: 'dividerColor',
replaceWith: 'color',
whitelist: {
elements: ['mat-form-field']
}
},
{
replace: 'floatPlaceholder',
replaceWith: 'floatLabel',
whitelist: {
elements: ['mat-form-field']
}
}
},
{
replace: 'floatPlaceholder',
replaceWith: 'floatLabel',
whitelist: {
elements: ['mat-form-field']
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10309',
changes: [
{
replace: 'mat-dynamic-height',
replaceWith: 'dynamicHeight',
whitelist: {
elements: ['mat-tab-group']
{
pr: 'https://github.com/angular/material2/pull/10309',
changes: [
{
replace: 'mat-dynamic-height',
replaceWith: 'dynamicHeight',
whitelist: {
elements: ['mat-tab-group']
}
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10342',
changes: [
{
replace: 'align',
replaceWith: 'labelPosition',
whitelist: {
elements: ['mat-checkbox']
{
pr: 'https://github.com/angular/material2/pull/10342',
changes: [
{
replace: 'align',
replaceWith: 'labelPosition',
whitelist: {
elements: ['mat-checkbox']
}
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10344',
changes: [
{
replace: 'tooltip-position',
replaceWith: 'matTooltipPosition',
whitelist: {
attributes: ['matTooltip']
{
pr: 'https://github.com/angular/material2/pull/10344',
changes: [
{
replace: 'tooltip-position',
replaceWith: 'matTooltipPosition',
whitelist: {
attributes: ['matTooltip']
}
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10373',
changes: [
{
replace: 'thumb-label',
replaceWith: 'thumbLabel',
whitelist: {
elements: ['mat-slider']
{
pr: 'https://github.com/angular/material2/pull/10373',
changes: [
{
replace: 'thumb-label',
replaceWith: 'thumbLabel',
whitelist: {
elements: ['mat-slider']
}
},
{
replace: 'tick-interval',
replaceWith: 'tickInterval',
whitelist: {
elements: ['mat-slider']
}
}
},
{
replace: 'tick-interval',
replaceWith: 'tickInterval',
whitelist: {
elements: ['mat-slider']
}
}
]
}
]);
]
}
]
};
@@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {transformChanges} from '../transform-change-data';
import {TargetVersion} from '../../index';
import {VersionChanges} from '../transform-change-data';
export interface MaterialMethodCallData {
className: string;
@@ -17,105 +18,107 @@ export interface MaterialMethodCallData {
}[];
}
export const methodCallChecks = transformChanges<MaterialMethodCallData>([
{
pr: 'https://github.com/angular/material2/pull/9190',
changes: [
{
className: 'NativeDateAdapter',
method: 'constructor',
invalidArgCounts: [
{
count: 1,
message: '"g{{platform}}" is now required as a second argument'
}
]
}
]
},
export const methodCallChecks: VersionChanges<MaterialMethodCallData> = {
[TargetVersion.V6]: [
{
pr: 'https://github.com/angular/material2/pull/9190',
changes: [
{
className: 'NativeDateAdapter',
method: 'constructor',
invalidArgCounts: [
{
count: 1,
message: '"g{{platform}}" is now required as a second argument'
}
]
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10319',
changes: [
{
className: 'MatAutocomplete',
method: 'constructor',
invalidArgCounts: [
{
count: 2,
message: '"g{{defaults}}" is now required as a third argument'
}
]
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10319',
changes: [
{
className: 'MatAutocomplete',
method: 'constructor',
invalidArgCounts: [
{
count: 2,
message: '"g{{defaults}}" is now required as a third argument'
}
]
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10325',
changes: [
{
className: 'FocusMonitor',
method: 'monitor',
invalidArgCounts: [
{
count: 3,
message: 'The "r{{renderer}}" argument has been removed'
}
]
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10325',
changes: [
{
className: 'FocusMonitor',
method: 'monitor',
invalidArgCounts: [
{
count: 3,
message: 'The "r{{renderer}}" argument has been removed'
}
]
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10344',
changes: [
{
className: 'MatTooltip',
method: 'constructor',
invalidArgCounts: [
{
count: 11,
message: '"g{{_defaultOptions}}" is now required as a twelfth argument'
}
]
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10344',
changes: [
{
className: 'MatTooltip',
method: 'constructor',
invalidArgCounts: [
{
count: 11,
message: '"g{{_defaultOptions}}" is now required as a twelfth argument'
}
]
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10389',
changes: [
{
className: 'MatIconRegistry',
method: 'constructor',
invalidArgCounts: [
{
count: 2,
message: '"g{{document}}" is now required as a third argument'
}
]
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10389',
changes: [
{
className: 'MatIconRegistry',
method: 'constructor',
invalidArgCounts: [
{
count: 2,
message: '"g{{document}}" is now required as a third argument'
}
]
}
]
},
{
pr: 'https://github.com/angular/material2/pull/9775',
changes: [
{
className: 'MatCalendar',
method: 'constructor',
invalidArgCounts: [
{
count: 6,
message: '"r{{_elementRef}}" and "r{{_ngZone}}" arguments have been removed'
},
{
count: 7,
message: '"r{{_elementRef}}", "r{{_ngZone}}", and "r{{_dir}}" arguments have been ' +
'removed'
}
]
}
]
}
]);
{
pr: 'https://github.com/angular/material2/pull/9775',
changes: [
{
className: 'MatCalendar',
method: 'constructor',
invalidArgCounts: [
{
count: 6,
message: '"r{{_elementRef}}" and "r{{_ngZone}}" arguments have been removed'
},
{
count: 7,
message: '"r{{_elementRef}}", "r{{_ngZone}}", and "r{{_dir}}" arguments have been ' +
'removed'
}
]
}
]
}
]
};
@@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {transformChanges} from '../transform-change-data';
import {TargetVersion} from '../../index';
import {VersionChanges} from '../transform-change-data';
export interface MaterialOutputNameData {
/** The @Output() name to replace. */
@@ -22,93 +23,95 @@ export interface MaterialOutputNameData {
};
}
export const outputNames = transformChanges<MaterialOutputNameData>([
{
pr: 'https://github.com/angular/material2/pull/10163',
changes: [
{
replace: 'change',
replaceWith: 'selectionChange',
whitelist: {
elements: ['mat-select']
}
},
{
replace: 'onClose',
replaceWith: 'closed',
whitelist: {
elements: ['mat-select']
}
},
{
replace: 'onOpen',
replaceWith: 'opened',
whitelist: {
elements: ['mat-select']
}
}
]
},
export const outputNames: VersionChanges<MaterialOutputNameData> = {
[TargetVersion.V6]: [
{
pr: 'https://github.com/angular/material2/pull/10163',
changes: [
{
replace: 'change',
replaceWith: 'selectionChange',
whitelist: {
elements: ['mat-select'],
},
},
{
replace: 'onClose',
replaceWith: 'closed',
whitelist: {
elements: ['mat-select'],
},
},
{
replace: 'onOpen',
replaceWith: 'opened',
whitelist: {
elements: ['mat-select'],
},
},
],
},
{
pr: 'https://github.com/angular/material2/pull/10279',
changes: [
{
replace: 'align-changed',
replaceWith: 'positionChanged',
whitelist: {
elements: ['mat-drawer', 'mat-sidenav']
}
},
{
replace: 'close',
replaceWith: 'closed',
whitelist: {
elements: ['mat-drawer', 'mat-sidenav']
}
},
{
replace: 'open',
replaceWith: 'opened',
whitelist: {
elements: ['mat-drawer', 'mat-sidenav']
}
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10279',
changes: [
{
replace: 'align-changed',
replaceWith: 'positionChanged',
whitelist: {
elements: ['mat-drawer', 'mat-sidenav'],
},
},
{
replace: 'close',
replaceWith: 'closed',
whitelist: {
elements: ['mat-drawer', 'mat-sidenav'],
},
},
{
replace: 'open',
replaceWith: 'opened',
whitelist: {
elements: ['mat-drawer', 'mat-sidenav'],
},
},
],
},
{
pr: 'https://github.com/angular/material2/pull/10309',
changes: [
{
replace: 'selectChange',
replaceWith: 'selectedTabChange',
whitelist: {
elements: ['mat-tab-group']
}
}
]
},
{
pr: 'https://github.com/angular/material2/pull/10309',
changes: [
{
replace: 'selectChange',
replaceWith: 'selectedTabChange',
whitelist: {
elements: ['mat-tab-group'],
},
},
],
},
{
pr: 'https://github.com/angular/material2/pull/10311',
changes: [
{
replace: 'remove',
replaceWith: 'removed',
whitelist: {
attributes: ['mat-chip', 'mat-basic-chip'],
elements: ['mat-chip', 'mat-basic-chip']
}
},
{
replace: 'destroy',
replaceWith: 'destroyed',
whitelist: {
attributes: ['mat-chip', 'mat-basic-chip'],
elements: ['mat-chip', 'mat-basic-chip']
}
}
]
}
]);
{
pr: 'https://github.com/angular/material2/pull/10311',
changes: [
{
replace: 'remove',
replaceWith: 'removed',
whitelist: {
attributes: ['mat-chip', 'mat-basic-chip'],
elements: ['mat-chip', 'mat-basic-chip'],
},
},
{
replace: 'destroy',
replaceWith: 'destroyed',
whitelist: {
attributes: ['mat-chip', 'mat-basic-chip'],
elements: ['mat-chip', 'mat-basic-chip'],
},
},
],
},
],
};
@@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {transformChanges} from '../transform-change-data';
import {TargetVersion} from '../../index';
import {VersionChanges} from '../transform-change-data';
export interface MaterialPropertyNameData {
/** The property name to replace. */
@@ -20,320 +21,322 @@ export interface MaterialPropertyNameData {
};
}
export const propertyNames = transformChanges<MaterialPropertyNameData>([
{
pr: 'https://github.com/angular/material2/pull/10161',
changes: [
{
replace: '_deprecatedOrigin',
replaceWith: 'origin',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
export const propertyNames: VersionChanges<MaterialPropertyNameData> = {
[TargetVersion.V6]: [
{
pr: 'https://github.com/angular/material2/pull/10161',
changes: [
{
replace: '_deprecatedOrigin',
replaceWith: 'origin',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedPositions',
replaceWith: 'positions',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedOffsetX',
replaceWith: 'offsetX',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedOffsetY',
replaceWith: 'offsetY',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedWidth',
replaceWith: 'width',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedHeight',
replaceWith: 'height',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedMinWidth',
replaceWith: 'minWidth',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedMinHeight',
replaceWith: 'minHeight',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedBackdropClass',
replaceWith: 'backdropClass',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedScrollStrategy',
replaceWith: 'scrollStrategy',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedOpen',
replaceWith: 'open',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedHasBackdrop',
replaceWith: 'hasBackdrop',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
}
},
{
replace: '_deprecatedPositions',
replaceWith: 'positions',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedOffsetX',
replaceWith: 'offsetX',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedOffsetY',
replaceWith: 'offsetY',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedWidth',
replaceWith: 'width',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedHeight',
replaceWith: 'height',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedMinWidth',
replaceWith: 'minWidth',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedMinHeight',
replaceWith: 'minHeight',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedBackdropClass',
replaceWith: 'backdropClass',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedScrollStrategy',
replaceWith: 'scrollStrategy',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedOpen',
replaceWith: 'open',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
},
{
replace: '_deprecatedHasBackdrop',
replaceWith: 'hasBackdrop',
whitelist: {
classes: ['CdkConnectedOverlay', 'ConnectedOverlayDirective']
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10163',
changes: [
{
replace: 'change',
replaceWith: 'selectionChange',
whitelist: {
classes: ['MatSelect']
{
pr: 'https://github.com/angular/material2/pull/10163',
changes: [
{
replace: 'change',
replaceWith: 'selectionChange',
whitelist: {
classes: ['MatSelect']
}
},
{
replace: 'onOpen',
replaceWith: 'openedChange.pipe(filter(isOpen => isOpen))',
whitelist: {
classes: ['MatSelect']
}
},
{
replace: 'onClose',
replaceWith: 'openedChange.pipe(filter(isOpen => !isOpen))',
whitelist: {
classes: ['MatSelect']
}
}
},
{
replace: 'onOpen',
replaceWith: 'openedChange.pipe(filter(isOpen => isOpen))',
whitelist: {
classes: ['MatSelect']
}
},
{
replace: 'onClose',
replaceWith: 'openedChange.pipe(filter(isOpen => !isOpen))',
whitelist: {
classes: ['MatSelect']
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10218',
changes: [
{
replace: 'align',
replaceWith: 'labelPosition',
whitelist: {
classes: ['MatRadioGroup', 'MatRadioButton']
{
pr: 'https://github.com/angular/material2/pull/10218',
changes: [
{
replace: 'align',
replaceWith: 'labelPosition',
whitelist: {
classes: ['MatRadioGroup', 'MatRadioButton']
}
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10253',
changes: [
{
replace: 'extraClasses',
replaceWith: 'panelClass',
whitelist: {
classes: ['MatSnackBarConfig']
{
pr: 'https://github.com/angular/material2/pull/10253',
changes: [
{
replace: 'extraClasses',
replaceWith: 'panelClass',
whitelist: {
classes: ['MatSnackBarConfig']
}
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10257',
changes: [
{
replace: '_deprecatedPortal',
replaceWith: 'portal',
whitelist: {
classes: ['CdkPortalOutlet']
{
pr: 'https://github.com/angular/material2/pull/10257',
changes: [
{
replace: '_deprecatedPortal',
replaceWith: 'portal',
whitelist: {
classes: ['CdkPortalOutlet']
}
},
{
replace: '_deprecatedPortalHost',
replaceWith: 'portal',
whitelist: {
classes: ['CdkPortalOutlet']
}
}
},
{
replace: '_deprecatedPortalHost',
replaceWith: 'portal',
whitelist: {
classes: ['CdkPortalOutlet']
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10279',
changes: [
{
replace: 'align',
replaceWith: 'position',
whitelist: {
classes: ['MatDrawer', 'MatSidenav']
{
pr: 'https://github.com/angular/material2/pull/10279',
changes: [
{
replace: 'align',
replaceWith: 'position',
whitelist: {
classes: ['MatDrawer', 'MatSidenav']
}
},
{
replace: 'onAlignChanged',
replaceWith: 'onPositionChanged',
whitelist: {
classes: ['MatDrawer', 'MatSidenav']
}
},
{
replace: 'onOpen',
replaceWith: 'openedChange.pipe(filter(isOpen => isOpen))',
whitelist: {
classes: ['MatDrawer', 'MatSidenav']
}
},
{
replace: 'onClose',
replaceWith: 'openedChange.pipe(filter(isOpen => !isOpen))',
whitelist: {
classes: ['MatDrawer', 'MatSidenav']
}
}
},
{
replace: 'onAlignChanged',
replaceWith: 'onPositionChanged',
whitelist: {
classes: ['MatDrawer', 'MatSidenav']
}
},
{
replace: 'onOpen',
replaceWith: 'openedChange.pipe(filter(isOpen => isOpen))',
whitelist: {
classes: ['MatDrawer', 'MatSidenav']
}
},
{
replace: 'onClose',
replaceWith: 'openedChange.pipe(filter(isOpen => !isOpen))',
whitelist: {
classes: ['MatDrawer', 'MatSidenav']
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10293',
changes: [
{
replace: 'shouldPlaceholderFloat',
replaceWith: 'shouldLabelFloat',
whitelist: {
classes: ['MatFormFieldControl', 'MatSelect']
{
pr: 'https://github.com/angular/material2/pull/10293',
changes: [
{
replace: 'shouldPlaceholderFloat',
replaceWith: 'shouldLabelFloat',
whitelist: {
classes: ['MatFormFieldControl', 'MatSelect']
}
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10294',
changes: [
{
replace: 'dividerColor',
replaceWith: 'color',
whitelist: {
classes: ['MatFormField']
{
pr: 'https://github.com/angular/material2/pull/10294',
changes: [
{
replace: 'dividerColor',
replaceWith: 'color',
whitelist: {
classes: ['MatFormField']
}
},
{
replace: 'floatPlaceholder',
replaceWith: 'floatLabel',
whitelist: {
classes: ['MatFormField']
}
}
},
{
replace: 'floatPlaceholder',
replaceWith: 'floatLabel',
whitelist: {
classes: ['MatFormField']
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10309',
changes: [
{
replace: 'selectChange',
replaceWith: 'selectedTabChange',
whitelist: {
classes: ['MatTabGroup']
{
pr: 'https://github.com/angular/material2/pull/10309',
changes: [
{
replace: 'selectChange',
replaceWith: 'selectedTabChange',
whitelist: {
classes: ['MatTabGroup']
}
},
{
replace: '_dynamicHeightDeprecated',
replaceWith: 'dynamicHeight',
whitelist: {
classes: ['MatTabGroup']
}
}
},
{
replace: '_dynamicHeightDeprecated',
replaceWith: 'dynamicHeight',
whitelist: {
classes: ['MatTabGroup']
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10311',
changes: [
{
replace: 'destroy',
replaceWith: 'destroyed',
whitelist: {
classes: ['MatChip']
{
pr: 'https://github.com/angular/material2/pull/10311',
changes: [
{
replace: 'destroy',
replaceWith: 'destroyed',
whitelist: {
classes: ['MatChip']
}
},
{
replace: 'onRemove',
replaceWith: 'removed',
whitelist: {
classes: ['MatChip']
}
}
},
{
replace: 'onRemove',
replaceWith: 'removed',
whitelist: {
classes: ['MatChip']
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10342',
changes: [
{
replace: 'align',
replaceWith: 'labelPosition',
whitelist: {
classes: ['MatCheckbox']
{
pr: 'https://github.com/angular/material2/pull/10342',
changes: [
{
replace: 'align',
replaceWith: 'labelPosition',
whitelist: {
classes: ['MatCheckbox']
}
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10344',
changes: [
{
replace: '_positionDeprecated',
replaceWith: 'position',
whitelist: {
classes: ['MatTooltip']
{
pr: 'https://github.com/angular/material2/pull/10344',
changes: [
{
replace: '_positionDeprecated',
replaceWith: 'position',
whitelist: {
classes: ['MatTooltip']
}
}
}
]
},
]
},
{
pr: 'https://github.com/angular/material2/pull/10373',
changes: [
{
replace: '_thumbLabelDeprecated',
replaceWith: 'thumbLabel',
whitelist: {
classes: ['MatSlider']
{
pr: 'https://github.com/angular/material2/pull/10373',
changes: [
{
replace: '_thumbLabelDeprecated',
replaceWith: 'thumbLabel',
whitelist: {
classes: ['MatSlider']
}
},
{
replace: '_tickIntervalDeprecated',
replaceWith: 'tickInterval',
whitelist: {
classes: ['MatSlider']
}
}
},
{
replace: '_tickIntervalDeprecated',
replaceWith: 'tickInterval',
whitelist: {
classes: ['MatSlider']
}
}
]
}
]);
]
}
]
};
@@ -5,6 +5,11 @@
* 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 {TargetVersion} from '../index';
export type VersionChanges<T> = {
[target in TargetVersion]?: ReadableChange<T>[];
};
export type ReadableChange<T> = {
pr: string;
@@ -12,10 +17,21 @@ export type ReadableChange<T> = {
};
/**
* For readability and a good overview of breaking changes, the changes data always includes
* the related Pull Request link. Since this data is not needed when performing the upgrade, this
* data can be removed and the changes data can be flattened into a easy queryable array.
* Gets the changes for a given target version from the specified version changes object.
*
* For readability and a good overview of breaking changes, the version change data always
* includes the related Pull Request link. Since this data is not needed when performing the
* upgrade, this unused data can be removed and the changes data can be flattened into an
* easy iterable array.
*/
export function transformChanges<T>(allChanges: ReadableChange<T>[]): T[] {
return allChanges.reduce((result, changes) => result.concat(changes.changes), []);
export function getChangesForTarget<T>(target: TargetVersion, data: VersionChanges<T>): T[] {
if (!data) {
throw new Error(`No data could be found for target version: ${TargetVersion[target]}`);
}
if (!data[target]) {
return [];
}
return data[target].reduce((result, changes) => result.concat(changes.changes), []);
}
@@ -12,6 +12,7 @@ import {
attributeSelectors,
MaterialAttributeSelectorData,
} from '../../material/data/attribute-selectors';
import {getChangesForTarget} from '../../material/transform-change-data';
import {findAllSubstringIndices} from '../../typescript/literal';
import * as ts from 'typescript';
@@ -27,6 +28,9 @@ export class Rule extends Rules.AbstractRule {
class Walker extends RuleWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], attributeSelectors);
visitStringLiteral(literal: ts.StringLiteral) {
if (literal.parent && literal.parent.kind !== ts.SyntaxKind.CallExpression) {
return;
@@ -34,7 +38,7 @@ class Walker extends RuleWalker {
const literalText = literal.getFullText();
attributeSelectors.forEach(selector => {
this.data.forEach(selector => {
findAllSubstringIndices(literalText, selector.replace)
.map(offset => literal.getStart() + offset)
.map(start => new Replacement(start, selector.replace.length, selector.replaceWith))
@@ -10,6 +10,7 @@ import {green, red} from 'chalk';
import {sync as globSync} from 'glob';
import {IOptions, Replacement, RuleFailure, Rules} from 'tslint';
import {attributeSelectors} from '../../material/data/attribute-selectors';
import {getChangesForTarget} from '../../material/transform-change-data';
import {ExternalResource} from '../../tslint/component-file';
import {ComponentWalker} from '../../tslint/component-walker';
import {
@@ -32,13 +33,15 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends ComponentWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], attributeSelectors);
constructor(sourceFile: ts.SourceFile, options: IOptions) {
// In some applications, developers will have global stylesheets that are not specified in any
// Angular component. Therefore we glob up all css and scss files outside of node_modules and
// dist and check them as well.
const extraFiles = globSync('!(node_modules|dist)/**/*.+(css|scss)');
super(sourceFile, options, extraFiles);
extraFiles.forEach(styleUrl => this._reportExternalStyle(styleUrl));
super(sourceFile, options, globSync('!(node_modules|dist)/**/*.+(css|scss)'));
this._reportExtraStylesheetFiles();
}
visitInlineStylesheet(literal: ts.StringLiteral) {
@@ -60,7 +63,7 @@ export class Walker extends ComponentWalker {
private _createReplacementsForContent(node: ts.Node, stylesheetContent: string) {
const replacements: {failureMessage: string, replacement: Replacement}[] = [];
attributeSelectors.forEach(selector => {
this.data.forEach(selector => {
const currentSelector = `[${selector.replace}]`;
const updatedSelector = `[${selector.replaceWith}]`;
@@ -10,6 +10,7 @@ import {green, red} from 'chalk';
import {Replacement, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {attributeSelectors} from '../../material/data/attribute-selectors';
import {getChangesForTarget} from '../../material/transform-change-data';
import {ExternalResource} from '../../tslint/component-file';
import {ComponentWalker} from '../../tslint/component-walker';
import {
@@ -30,6 +31,9 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends ComponentWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], attributeSelectors);
visitInlineTemplate(template: ts.StringLiteral) {
this._createReplacementsForContent(template, template.getText())
.forEach(data => addFailureAtReplacement(this, data.failureMessage, data.replacement));
@@ -49,7 +53,7 @@ export class Walker extends ComponentWalker {
private _createReplacementsForContent(node: ts.Node, templateContent: string) {
const replacements: {failureMessage: string, replacement: Replacement}[] = [];
attributeSelectors.forEach(selector => {
this.data.forEach(selector => {
const failureMessage = `Found deprecated attribute selector "[${red(selector.replace)}]"` +
` which has been renamed to "[${green(selector.replaceWith)}]"`;
@@ -7,21 +7,12 @@
*/
import {bold, green, red} from 'chalk';
import {ProgramAwareRuleWalker, RuleFailure, Rules} from 'tslint';
import {IOptions, ProgramAwareRuleWalker, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {MaterialPropertyNameData, propertyNames} from '../../material/data/property-names';
import {getChangesForTarget} from '../../material/transform-change-data';
import {determineBaseTypes} from '../../typescript/base-types';
/**
* Map of classes that have been updated. Each class name maps to the according property change
* data.
*/
const changedClassesMap = new Map<string, MaterialPropertyNameData>();
propertyNames.filter(data => data.whitelist && data.whitelist.classes).forEach(data => {
data.whitelist.classes.forEach(name => changedClassesMap.set(name, data));
});
/**
* Rule that identifies class declarations that extend CDK or Material classes and had
* a public property change.
@@ -34,6 +25,20 @@ export class Rule extends Rules.TypedRule {
export class Walker extends ProgramAwareRuleWalker {
/**
* Map of classes that have been updated. Each class name maps to the according property
* change data.
*/
propertyNames = new Map<string, MaterialPropertyNameData>();
constructor(sourceFile: ts.SourceFile, options: IOptions, program: ts.Program) {
super(sourceFile, options, program);
getChangesForTarget(options.ruleArguments[0], propertyNames)
.filter(data => data.whitelist && data.whitelist.classes)
.forEach(data => data.whitelist.classes.forEach(name => this.propertyNames.set(name, data)));
}
visitClassDeclaration(node: ts.ClassDeclaration) {
const baseTypes = determineBaseTypes(node);
@@ -42,7 +47,7 @@ export class Walker extends ProgramAwareRuleWalker {
}
baseTypes.forEach(typeName => {
const data = changedClassesMap.get(typeName);
const data = this.propertyNames.get(typeName);
if (data) {
this.addFailureAtNode(node, `Found class "${bold(node.name.text)}" which extends class ` +
@@ -10,6 +10,7 @@ import {green, red} from 'chalk';
import {RuleFailure, Rules, RuleWalker} from 'tslint';
import * as ts from 'typescript';
import {classNames} from '../../material/data/class-names';
import {getChangesForTarget} from '../../material/transform-change-data';
import {
isMaterialExportDeclaration,
isMaterialImportDeclaration,
@@ -33,6 +34,9 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends RuleWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], classNames);
/**
* List of identifier names that have been imported from `@angular/material` or `@angular/cdk`
* in the current source file and therefore can be considered trusted.
@@ -46,7 +50,7 @@ export class Walker extends RuleWalker {
visitIdentifier(identifier: ts.Identifier) {
// For identifiers that aren't listed in the className data, the whole check can be
// skipped safely.
if (!classNames.some(data => data.replace === identifier.text)) {
if (!this.data.some(data => data.replace === identifier.text)) {
return;
}
@@ -89,7 +93,7 @@ export class Walker extends RuleWalker {
/** Creates a failure and replacement for the specified identifier. */
private _createFailureWithReplacement(identifier: ts.Identifier) {
const classData = classNames.find(data => data.replace === identifier.text);
const classData = this.data.find(data => data.replace === identifier.text);
if (!classData) {
console.error(`Could not find updated name for identifier "${identifier.text}" in ` +
@@ -10,6 +10,7 @@ import {green, red} from 'chalk';
import {Replacement, RuleFailure, Rules, RuleWalker} from 'tslint';
import * as ts from 'typescript';
import {cssSelectors, MaterialCssSelectorData} from '../../material/data/css-selectors';
import {getChangesForTarget} from '../../material/transform-change-data';
import {findAllSubstringIndices} from '../../typescript/literal';
/**
@@ -24,6 +25,9 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends RuleWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], cssSelectors);
visitStringLiteral(node: ts.StringLiteral) {
if (node.parent && node.parent.kind !== ts.SyntaxKind.CallExpression) {
return;
@@ -31,7 +35,7 @@ export class Walker extends RuleWalker {
const textContent = node.getFullText();
cssSelectors.forEach(data => {
this.data.forEach(data => {
if (data.whitelist && !data.whitelist.strings) {
return;
}
@@ -11,6 +11,7 @@ import {sync as globSync} from 'glob';
import {IOptions, Replacement, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {cssSelectors} from '../../material/data/css-selectors';
import {getChangesForTarget} from '../../material/transform-change-data';
import {ExternalResource} from '../../tslint/component-file';
import {ComponentWalker} from '../../tslint/component-walker';
import {
@@ -31,16 +32,17 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends ComponentWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], cssSelectors);
constructor(sourceFile: ts.SourceFile, options: IOptions) {
// In some applications, developers will have global stylesheets that are not specified in any
// Angular component. Therefore we glob up all css and scss files outside of node_modules and
// dist and check them as well.
const extraFiles = globSync('!(node_modules|dist)/**/*.+(css|scss)');
super(sourceFile, options, extraFiles);
extraFiles.forEach(styleUrl => this._reportExternalStyle(styleUrl));
super(sourceFile, options, globSync('!(node_modules|dist)/**/*.+(css|scss)'));
this._reportExtraStylesheetFiles();
}
visitInlineStylesheet(literal: ts.StringLiteral) {
this._createReplacementsForContent(literal, literal.getText())
.forEach(data => addFailureAtReplacement(this, data.failureMessage, data.replacement));
@@ -60,7 +62,7 @@ export class Walker extends ComponentWalker {
private _createReplacementsForContent(node: ts.Node, stylesheetContent: string) {
const replacements: {failureMessage: string, replacement: Replacement}[] = [];
cssSelectors.forEach(data => {
this.data.forEach(data => {
if (data.whitelist && !data.whitelist.stylesheet) {
return;
}
@@ -10,6 +10,7 @@ import {green, red} from 'chalk';
import {Replacement, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {cssSelectors} from '../../material/data/css-selectors';
import {getChangesForTarget} from '../../material/transform-change-data';
import {ExternalResource} from '../../tslint/component-file';
import {ComponentWalker} from '../../tslint/component-walker';
import {
@@ -30,6 +31,9 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends ComponentWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], cssSelectors);
visitInlineTemplate(template: ts.StringLiteral) {
this._createReplacementsForContent(template, template.getText())
.forEach(data => addFailureAtReplacement(this, data.failureMessage, data.replacement));
@@ -49,7 +53,7 @@ export class Walker extends ComponentWalker {
private _createReplacementsForContent(node: ts.Node, templateContent: string) {
const replacements: {failureMessage: string, replacement: Replacement}[] = [];
cssSelectors.forEach(data => {
this.data.forEach(data => {
if (data.whitelist && !data.whitelist.html) {
return;
}
@@ -10,6 +10,7 @@ import {green, red} from 'chalk';
import {Replacement, RuleFailure, Rules, RuleWalker} from 'tslint';
import * as ts from 'typescript';
import {elementSelectors, MaterialElementSelectorData} from '../../material/data/element-selectors';
import {getChangesForTarget} from '../../material/transform-change-data';
import {findAllSubstringIndices} from '../../typescript/literal';
/**
@@ -24,6 +25,9 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends RuleWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], elementSelectors);
visitStringLiteral(node: ts.StringLiteral) {
if (node.parent && node.parent.kind !== ts.SyntaxKind.CallExpression) {
return;
@@ -31,7 +35,7 @@ export class Walker extends RuleWalker {
const textContent = node.getFullText();
elementSelectors.forEach(selector => {
this.data.forEach(selector => {
findAllSubstringIndices(textContent, selector.replace)
.map(offset => node.getStart() + offset)
.map(start => new Replacement(start, selector.replace.length, selector.replaceWith))
@@ -11,6 +11,7 @@ import {sync as globSync} from 'glob';
import {IOptions, Replacement, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {elementSelectors} from '../../material/data/element-selectors';
import {getChangesForTarget} from '../../material/transform-change-data';
import {ExternalResource} from '../../tslint/component-file';
import {ComponentWalker} from '../../tslint/component-walker';
import {
@@ -31,13 +32,15 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends ComponentWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], elementSelectors);
constructor(sourceFile: ts.SourceFile, options: IOptions) {
// In some applications, developers will have global stylesheets that are not specified in any
// Angular component. Therefore we glob up all css and scss files outside of node_modules and
// dist and check them as well.
const extraFiles = globSync('!(node_modules|dist)/**/*.+(css|scss)');
super(sourceFile, options, extraFiles);
extraFiles.forEach(styleUrl => this._reportExternalStyle(styleUrl));
super(sourceFile, options, globSync('!(node_modules|dist)/**/*.+(css|scss)'));
this._reportExtraStylesheetFiles();
}
visitInlineStylesheet(literal: ts.StringLiteral) {
@@ -59,7 +62,7 @@ export class Walker extends ComponentWalker {
private _createReplacementsForContent(node: ts.Node, stylesheetContent: string) {
const replacements: {failureMessage: string, replacement: Replacement}[] = [];
elementSelectors.forEach(selector => {
this.data.forEach(selector => {
const failureMessage = `Found deprecated element selector "${red(selector.replace)}" ` +
`which has been renamed to "${green(selector.replaceWith)}"`;
@@ -10,6 +10,7 @@ import {green, red} from 'chalk';
import {Replacement, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {elementSelectors} from '../../material/data/element-selectors';
import {getChangesForTarget} from '../../material/transform-change-data';
import {ExternalResource} from '../../tslint/component-file';
import {ComponentWalker} from '../../tslint/component-walker';
import {
@@ -30,6 +31,9 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends ComponentWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], elementSelectors);
visitInlineTemplate(template: ts.StringLiteral) {
this._createReplacementsForContent(template, template.getText())
.forEach(data => addFailureAtReplacement(this, data.failureMessage, data.replacement));
@@ -49,7 +53,7 @@ export class Walker extends ComponentWalker {
private _createReplacementsForContent(node: ts.Node, templateContent: string) {
const replacements: {failureMessage: string, replacement: Replacement}[] = [];
elementSelectors.forEach(selector => {
this.data.forEach(selector => {
const failureMessage = `Found deprecated element selector "${red(selector.replace)}"` +
` which has been renamed to "${green(selector.replaceWith)}"`;
@@ -11,6 +11,7 @@ import {sync as globSync} from 'glob';
import {IOptions, Replacement, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {inputNames} from '../../material/data/input-names';
import {getChangesForTarget} from '../../material/transform-change-data';
import {ExternalResource} from '../../tslint/component-file';
import {ComponentWalker} from '../../tslint/component-walker';
import {
@@ -36,13 +37,15 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends ComponentWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], inputNames);
constructor(sourceFile: ts.SourceFile, options: IOptions) {
// In some applications, developers will have global stylesheets that are not specified in any
// Angular component. Therefore we glob up all css and scss files outside of node_modules and
// dist and check them as well.
const extraFiles = globSync('!(node_modules|dist)/**/*.+(css|scss)');
super(sourceFile, options, extraFiles);
extraFiles.forEach(styleUrl => this._reportExternalStyle(styleUrl));
super(sourceFile, options, globSync('!(node_modules|dist)/**/*.+(css|scss)'));
this._reportExtraStylesheetFiles();
}
visitInlineStylesheet(literal: ts.StringLiteral) {
@@ -64,7 +67,7 @@ export class Walker extends ComponentWalker {
private _createReplacementsForContent(node: ts.Node, stylesheetContent: string) {
const replacements: {failureMessage: string, replacement: Replacement}[] = [];
inputNames.forEach(name => {
this.data.forEach(name => {
if (name.whitelist && !name.whitelist.stylesheet) {
return;
}
@@ -11,6 +11,7 @@ import {Replacement, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {findInputsOnElementWithAttr, findInputsOnElementWithTag} from '../../html/angular';
import {inputNames} from '../../material/data/input-names';
import {getChangesForTarget} from '../../material/transform-change-data';
import {ExternalResource} from '../../tslint/component-file';
import {ComponentWalker} from '../../tslint/component-walker';
import {
@@ -30,6 +31,9 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends ComponentWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], inputNames);
visitInlineTemplate(template: ts.StringLiteral) {
this._createReplacementsForContent(template, template.getText())
.forEach(data => addFailureAtReplacement(this, data.failureMessage, data.replacement));
@@ -49,7 +53,7 @@ export class Walker extends ComponentWalker {
private _createReplacementsForContent(node: ts.Node, templateContent: string) {
const replacements: {failureMessage: string, replacement: Replacement}[] = [];
inputNames.forEach(name => {
this.data.forEach(name => {
const whitelist = name.whitelist;
const relativeOffsets = [];
const failureMessage = `Found deprecated @Input() "${red(name.replace)}"` +
@@ -11,6 +11,7 @@ import {ProgramAwareRuleWalker, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {color} from '../../material/color';
import {methodCallChecks} from '../../material/data/method-call-checks';
import {getChangesForTarget} from '../../material/transform-change-data';
/**
* Rule that visits every TypeScript call expression or TypeScript new expression and checks
@@ -24,6 +25,9 @@ export class Rule extends Rules.TypedRule {
export class Walker extends ProgramAwareRuleWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], methodCallChecks);
visitNewExpression(expression: ts.NewExpression) {
const classType = this.getTypeChecker().getTypeAtLocation(expression);
@@ -64,7 +68,7 @@ export class Walker extends ProgramAwareRuleWalker {
return;
}
const failure = methodCallChecks
const failure = this.data
.filter(data => data.method === methodName && data.className === hostTypeName)
.map(data => data.invalidArgCounts.find(f => f.count === node.arguments.length))[0];
@@ -78,7 +82,7 @@ export class Walker extends ProgramAwareRuleWalker {
private checkConstructor(node: ts.NewExpression | ts.CallExpression, className: string) {
const argumentsLength = node.arguments ? node.arguments.length : 0;
const failure = methodCallChecks
const failure = this.data
.filter(data => data.method === 'constructor' && data.className === className)
.map(data => data.invalidArgCounts.find(f => f.count === argumentsLength))[0];
@@ -11,6 +11,7 @@ import {Replacement, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {findOutputsOnElementWithAttr, findOutputsOnElementWithTag} from '../../html/angular';
import {outputNames} from '../../material/data/output-names';
import {getChangesForTarget} from '../../material/transform-change-data';
import {ExternalResource} from '../../tslint/component-file';
import {ComponentWalker} from '../../tslint/component-walker';
import {
@@ -30,6 +31,9 @@ export class Rule extends Rules.AbstractRule {
export class Walker extends ComponentWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], outputNames);
visitInlineTemplate(template: ts.StringLiteral) {
this._createReplacementsForContent(template, template.getText())
.forEach(data => addFailureAtReplacement(this, data.failureMessage, data.replacement));
@@ -49,7 +53,7 @@ export class Walker extends ComponentWalker {
private _createReplacementsForContent(node: ts.Node, templateContent: string) {
const replacements: {failureMessage: string, replacement: Replacement}[] = [];
outputNames.forEach(name => {
this.data.forEach(name => {
const whitelist = name.whitelist;
const relativeOffsets = [];
const failureMessage = `Found deprecated @Output() "${red(name.replace)}"` +
@@ -10,6 +10,7 @@ import {green, red} from 'chalk';
import {ProgramAwareRuleWalker, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {propertyNames} from '../../material/data/property-names';
import {getChangesForTarget} from '../../material/transform-change-data';
/**
* Rule that walks through every property access expression and updates properties that have
@@ -23,11 +24,14 @@ export class Rule extends Rules.TypedRule {
export class Walker extends ProgramAwareRuleWalker {
/** Change data that upgrades to the specified target version. */
data = getChangesForTarget(this.getOptions()[0], propertyNames);
visitPropertyAccessExpression(node: ts.PropertyAccessExpression) {
const hostType = this.getTypeChecker().getTypeAtLocation(node.expression);
const typeName = hostType && hostType.symbol && hostType.symbol.getName();
propertyNames.forEach(data => {
this.data.forEach(data => {
if (node.name.text !== data.replace) {
return;
}
@@ -16,12 +16,6 @@ describe('test cases', () => {
*/
const testCases = [
'v5/attribute-selectors',
'v5/class-names',
'v5/css-names',
'v5/element-selectors',
'v5/input-names',
'v5/output-names',
'v5/property-names',
];
// Iterates through every test case directory and generates a jasmine test block that will
@@ -28,11 +28,12 @@ export class ComponentWalker extends RuleWalker {
protected visitExternalTemplate(_template: ExternalResource) {}
protected visitExternalStylesheet(_stylesheet: ExternalResource) {}
private skipFiles: Set<string>;
private extraFiles: Set<string>;
constructor(sourceFile: ts.SourceFile, options: IOptions, skipFiles: string[] = []) {
constructor(sourceFile: ts.SourceFile, options: IOptions, extraFiles: string[] = []) {
super(sourceFile, options);
this.skipFiles = new Set(skipFiles.map(p => resolve(p)));
this.extraFiles = new Set(extraFiles.map(p => resolve(p)));
}
visitNode(node: ts.Node) {
@@ -95,7 +96,8 @@ export class ComponentWalker extends RuleWalker {
const styleUrl = getLiteralTextWithoutQuotes(styleUrlLiteral as ts.StringLiteral);
const stylePath = resolve(join(dirname(this.getSourceFile().fileName), styleUrl));
if (!this.skipFiles.has(stylePath)) {
// Do not report the specified additional files multiple times.
if (!this.extraFiles.has(stylePath)) {
this._reportExternalStyle(stylePath);
}
});
@@ -105,7 +107,8 @@ export class ComponentWalker extends RuleWalker {
const templateUrl = getLiteralTextWithoutQuotes(templateUrlLiteral);
const templatePath = resolve(join(dirname(this.getSourceFile().fileName), templateUrl));
if (this.skipFiles.has(templatePath)) {
// Do not report the specified additional files multiple times.
if (this.extraFiles.has(templatePath)) {
return;
}
@@ -136,6 +139,13 @@ export class ComponentWalker extends RuleWalker {
this.visitExternalStylesheet(stylesheetFile);
}
/** Reports all extra files that have been specified at initialization. */
// TODO(devversion): this should be done automatically but deferred because
// the base class "data" property member is not ready at initialization.
_reportExtraStylesheetFiles() {
this.extraFiles.forEach(file => this._reportExternalStyle(file));
}
/**
* Recursively searches for the metadata object literal expression inside of a directive call
* expression. Since expression calls can be nested through *parenthesized* expressions, we