Skip to content

Commit 73135d8

Browse files
committed
refactor(schematics): cleanup remaining rules
* Fixes that the `method-check` rule does not throw if the type of a class instantiation could not be determined. * Cleans up the remaining rules. * Removes the `exportAs` rule for now. Since it's unused and also extremely brittle (search & replace). * Fixes that the template misc rule reports wrong line numbers for external templates.
1 parent c09da0b commit 73135d8

File tree

11 files changed

+222
-309
lines changed

11 files changed

+222
-309
lines changed

src/lib/schematics/update/material/data/export-as-names.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/lib/schematics/update/material/data/method-call-checks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const methodCallChecks = transformChanges<MaterialMethodCallData>([
4343
invalidArgCounts: [
4444
{
4545
count: 2,
46-
message: '"g{{default}}" is now required as a third argument'
46+
message: '"g{{defaults}}" is now required as a third argument'
4747
}
4848
]
4949
}

src/lib/schematics/update/rules/checkClassDeclarationMiscRule.ts

Lines changed: 0 additions & 44 deletions
This file was deleted.

src/lib/schematics/update/rules/checkMethodCallsRule.ts

Lines changed: 0 additions & 92 deletions
This file was deleted.

src/lib/schematics/update/rules/checkTemplateMiscRule.ts

Lines changed: 46 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,76 +15,69 @@ import {ComponentWalker} from '../tslint/component-walker';
1515
import {findAllSubstringIndices} from '../typescript/literal';
1616

1717
/**
18-
* Rule that walks through every component decorator and updates their inline or external
19-
* templates.
18+
* Rule that walks through every inline or external template and reports if there are outdated
19+
* usages of the Angular Material API that need to be updated manually.
2020
*/
2121
export class Rule extends Rules.AbstractRule {
2222
apply(sourceFile: ts.SourceFile): RuleFailure[] {
23-
return this.applyWithWalker(new CheckTemplateMiscWalker(sourceFile, this.getOptions()));
23+
return this.applyWithWalker(new Walker(sourceFile, this.getOptions()));
2424
}
2525
}
2626

27-
export class CheckTemplateMiscWalker extends ComponentWalker {
27+
export class Walker extends ComponentWalker {
28+
2829
visitInlineTemplate(template: ts.StringLiteral) {
29-
this.checkTemplate(template.getText()).forEach(failure => {
30-
const ruleFailure = new RuleFailure(template.getSourceFile(), failure.start, failure.end,
31-
failure.message, this.getRuleName());
32-
this.addFailure(ruleFailure);
33-
});
30+
this._createFailuresForContent(template, template.getText())
31+
.forEach(data => this.addFailureFromStartToEnd(data.start, data.end, data.message));
3432
}
3533

3634
visitExternalTemplate(template: ExternalResource) {
37-
this.checkTemplate(template.getFullText()).forEach(failure => {
38-
const ruleFailure = new RuleFailure(template, failure.start + 1, failure.end + 1,
39-
failure.message, this.getRuleName());
40-
this.addFailure(ruleFailure);
35+
this._createFailuresForContent(template, template.getFullText()).forEach(data => {
36+
this.addFailure(new RuleFailure(
37+
template, data.start, data.end, data.message, this.getRuleName()));
4138
});
4239
}
4340

44-
/**
45-
* Replaces the outdated name in the template with the new one and returns an updated template.
46-
*/
47-
private checkTemplate(templateContent: string):
48-
{start: number, end: number, message: string}[] {
49-
let failures: {message: string, start: number, end: number}[] = [];
41+
private _createFailuresForContent(node: ts.Node, content: string) {
42+
const failures: {message: string, start: number, end: number}[] = [];
5043

51-
failures = failures.concat(
52-
findAllSubstringIndices(templateContent, 'cdk-focus-trap').map(offset => ({
53-
start: offset,
54-
end: offset + 'cdk-focus-trap'.length,
55-
message: `Found deprecated element selector "${red('cdk-focus-trap')}" which has been` +
56-
` changed to an attribute selector "${green('[cdkTrapFocus]')}"`
57-
}))
58-
);
44+
findAllSubstringIndices(content, 'cdk-focus-trap').forEach(offset => {
45+
failures.push({
46+
start: node.getStart() + offset,
47+
end: node.getStart() + offset + 'cdk-focus-trap'.length,
48+
message: `Found deprecated element selector "${red('cdk-focus-trap')}" which has been ` +
49+
`changed to an attribute selector "${green('[cdkTrapFocus]')}".`
50+
});
51+
});
5952

60-
failures = failures.concat(
61-
findOutputsOnElementWithTag(templateContent, 'selectionChange', ['mat-list-option'])
62-
.map(offset => ({
63-
start: offset,
64-
end: offset + 'selectionChange'.length,
65-
message: `Found deprecated @Output() "${red('selectionChange')}" on` +
66-
` "${bold('mat-list-option')}". Use "${green('selectionChange')}" on` +
67-
` "${bold('mat-selection-list')}" instead`
68-
})));
53+
findOutputsOnElementWithTag(content, 'selectionChange', ['mat-list-option']).forEach(offset => {
54+
failures.push({
55+
start: node.getStart() + offset,
56+
end: node.getStart() + offset + 'selectionChange'.length,
57+
message: `Found deprecated @Output() "${red('selectionChange')}" on ` +
58+
`"${bold('mat-list-option')}". Use "${green('selectionChange')}" on ` +
59+
`"${bold('mat-selection-list')}" instead.`
60+
});
61+
});
6962

70-
failures = failures.concat(
71-
findOutputsOnElementWithTag(templateContent, 'selectedChanged', ['mat-datepicker'])
72-
.map(offset => ({
73-
start: offset,
74-
end: offset + 'selectionChange'.length,
75-
message: `Found deprecated @Output() "${red('selectedChanged')}" on` +
76-
` "${bold('mat-datepicker')}". Use "${green('dateChange')}" or` +
77-
` "${green('dateInput')}" on "${bold('<input [matDatepicker]>')}" instead`
78-
})));
63+
findOutputsOnElementWithTag(content, 'selectedChanged', ['mat-datepicker']).forEach(offset => {
64+
failures.push({
65+
start: node.getStart() + offset,
66+
end: node.getStart() + offset + 'selectionChange'.length,
67+
message: `Found deprecated @Output() "${red('selectedChanged')}" on ` +
68+
`"${bold('mat-datepicker')}". Use "${green('dateChange')}" or ` +
69+
`"${green('dateInput')}" on "${bold('<input [matDatepicker]>')}" instead.`
70+
});
71+
});
7972

80-
failures = failures.concat(
81-
findInputsOnElementWithTag(templateContent, 'selected', ['mat-button-toggle-group'])
82-
.map(offset => ({
83-
start: offset,
84-
end: offset + 'selected'.length,
85-
message: `Found deprecated @Input() "${red('selected')}" on` +
86-
` "${bold('mat-radio-button-group')}". Use "${green('value')}" instead`
87-
})));
73+
findInputsOnElementWithTag(content, 'selected', ['mat-button-toggle-group']).forEach(offset => {
74+
failures.push({
75+
start: node.getStart() + offset,
76+
end: node.getStart() + offset + 'selected'.length,
77+
message: `Found deprecated @Input() "${red('selected')}" on ` +
78+
`"${bold('mat-radio-button-group')}". Use "${green('value')}" instead.`
79+
});
80+
});
8881

8982
return failures;
9083
}

src/lib/schematics/update/rules/checkInheritanceRule.ts renamed to src/lib/schematics/update/rules/class-inheritance/classInheritanceCheckRule.ts

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
import {bold, green, red} from 'chalk';
1010
import {ProgramAwareRuleWalker, RuleFailure, Rules} from 'tslint';
1111
import * as ts from 'typescript';
12-
import {MaterialPropertyNameData, propertyNames} from '../material/data/property-names';
12+
import {MaterialPropertyNameData, propertyNames} from '../../material/data/property-names';
13+
import {determineBaseTypes} from '../../typescript/base-types';
1314

1415
/**
1516
* Map of classes that have been updated. Each class name maps to the according property change
@@ -34,7 +35,7 @@ export class Rule extends Rules.TypedRule {
3435
export class Walker extends ProgramAwareRuleWalker {
3536

3637
visitClassDeclaration(node: ts.ClassDeclaration) {
37-
const baseTypes = this._determineBaseTypes(node);
38+
const baseTypes = determineBaseTypes(node);
3839

3940
if (!baseTypes) {
4041
return;
@@ -44,24 +45,11 @@ export class Walker extends ProgramAwareRuleWalker {
4445
const data = changedClassesMap.get(typeName);
4546

4647
if (data) {
47-
this.addFailureAtNode(node,
48-
`Found class "${bold(node.name.text)}" which extends class ` +
49-
`"${bold(typeName)}". Please note that the base class property ` +
50-
`"${red(data.replace)}" has changed to "${green(data.replaceWith)}". ` +
51-
`You may need to update your class as well`);
48+
this.addFailureAtNode(node, `Found class "${bold(node.name.text)}" which extends class ` +
49+
`"${bold(typeName)}". Please note that the base class property ` +
50+
`"${red(data.replace)}" has changed to "${green(data.replaceWith)}". ` +
51+
`You may need to update your class as well`);
5252
}
5353
});
5454
}
55-
56-
private _determineBaseTypes(node: ts.ClassDeclaration): string[] | null {
57-
if (!node.heritageClauses) {
58-
return null;
59-
}
60-
61-
return node.heritageClauses
62-
.reduce((types, clause) => types.concat(clause.types), [])
63-
.map(typeExpression => typeExpression.expression)
64-
.filter(expression => expression && ts.isIdentifier(expression))
65-
.map(identifier => identifier.text);
66-
}
6755
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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 {bold, green} from 'chalk';
10+
import {ProgramAwareRuleWalker, RuleFailure, Rules} from 'tslint';
11+
import * as ts from 'typescript';
12+
import {determineBaseTypes} from '../../typescript/base-types';
13+
14+
/**
15+
* Rule that checks for classes that extend Angular Material or CDK classes which have
16+
* changed their API.
17+
*/
18+
export class Rule extends Rules.TypedRule {
19+
applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[] {
20+
return this.applyWithWalker(new Walker(sourceFile, this.getOptions(), program));
21+
}
22+
}
23+
24+
export class Walker extends ProgramAwareRuleWalker {
25+
26+
visitClassDeclaration(node: ts.ClassDeclaration) {
27+
const baseTypes = determineBaseTypes(node);
28+
29+
if (!baseTypes) {
30+
return;
31+
}
32+
33+
if (baseTypes.includes('MatFormFieldControl')) {
34+
const hasFloatLabelMember = node.members
35+
.find(member => member.name && member.name.getText() === 'shouldFloatLabel');
36+
37+
if (!hasFloatLabelMember) {
38+
this.addFailureAtNode(node, `Found class "${bold(node.name.text)}" which extends ` +
39+
`"${bold('MatFormFieldControl')}". This class must define ` +
40+
`"${green('shouldLabelFloat')}" which is now a required property.`);
41+
}
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)