Skip to content

Commit de45fc0

Browse files
crisbetojelbourn
authored andcommitted
build: add rule to enforce static queries (#15963)
Adds a simplified tslint rule to enforce that we've explicitly set the `static` flag on relevant queries. We don't need the more advanced functionality from the one in angular/angular, because we don't have to figure out which value is correct, only that it is set.
1 parent 8ab0f63 commit de45fc0

File tree

5 files changed

+42
-3
lines changed

5 files changed

+42
-3
lines changed

src/cdk-experimental/popover-edit/popover-edit.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ interface PeriodicElement {
5454
}
5555

5656
abstract class BaseTestComponent {
57-
@ViewChild('table') table: ElementRef;
57+
@ViewChild('table', {static: false}) table: ElementRef;
5858

5959
preservedValues = new Map<number, PeriodicElement>();
6060

src/material-experimental/mdc-checkbox/checkbox.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1050,7 +1050,7 @@ class CheckboxWithTabIndex {
10501050
<mat-checkbox></mat-checkbox>`,
10511051
})
10521052
class CheckboxUsingViewChild {
1053-
@ViewChild(MatCheckbox) checkbox: MatCheckbox;
1053+
@ViewChild(MatCheckbox, {static: false}) checkbox: MatCheckbox;
10541054

10551055
set isDisabled(value: boolean) {
10561056
this.checkbox.disabled = value;

src/material-experimental/popover-edit/popover-edit.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ interface PeriodicElement {
5858
}
5959

6060
abstract class BaseTestComponent {
61-
@ViewChild('table') table: ElementRef;
61+
@ViewChild('table', {static: false}) table: ElementRef;
6262

6363
preservedValues = new Map<number, PeriodicElement>();
6464

tools/tslint-rules/staticQueryRule.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import * as ts from 'typescript';
2+
import * as Lint from 'tslint';
3+
4+
/**
5+
* Rule which enforces that all queries are explicitly marked as static or non-static.
6+
*/
7+
export class Rule extends Lint.Rules.AbstractRule {
8+
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
9+
return this.applyWithWalker(new Walker(sourceFile, this.getOptions()));
10+
}
11+
}
12+
13+
class Walker extends Lint.RuleWalker {
14+
visitPropertyDeclaration(node: ts.PropertyDeclaration) {
15+
const childQueryDecorator = node.decorators && node.decorators.find(decorator => {
16+
const expression = (decorator.expression as ts.CallExpression);
17+
const name = expression && expression.expression.getText();
18+
return name === 'ViewChild' || name === 'ContentChild';
19+
});
20+
21+
if (childQueryDecorator) {
22+
const options = (childQueryDecorator.expression as ts.CallExpression).arguments[1];
23+
24+
if (!options || !ts.isObjectLiteralExpression(options) ||
25+
!this._getObjectProperty(options, 'static')) {
26+
this.addFailureAtNode(childQueryDecorator,
27+
'Queries have to explicitly set the `static` option.');
28+
}
29+
}
30+
31+
super.visitPropertyDeclaration(node);
32+
}
33+
34+
/** Gets the node of an object property by name. */
35+
private _getObjectProperty(node: ts.ObjectLiteralExpression, name: string) {
36+
return node.properties.find(property => (property.name as ts.Identifier).getText() === name);
37+
}
38+
}

tslint.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"ng-on-changes-property-access": true,
103103
"rxjs-imports": true,
104104
"require-breaking-change-version": true,
105+
"static-query": true,
105106
"no-host-decorator-in-concrete": [
106107
true,
107108
"HostBinding",

0 commit comments

Comments
 (0)