1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
import * as _ from 'lodash';
import * as Lint from 'tslint';
import * as ts from 'typescript';
const VALID_BOOLEAN_PREFIXES = ['is', 'does', 'should', 'was', 'has', 'can', 'did', 'would', 'are'];
export class Rule extends Lint.Rules.TypedRule {
public static FAILURE_STRING = `Boolean variable names should begin with: ${VALID_BOOLEAN_PREFIXES.join(', ')}`;
public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}
function walk(ctx: Lint.WalkContext<void>, tc: ts.TypeChecker): void {
traverse(ctx.sourceFile);
function traverse(node: ts.Node): void {
checkNodeForViolations(ctx, node, tc);
return ts.forEachChild(node, traverse);
}
}
function checkNodeForViolations(ctx: Lint.WalkContext<void>, node: ts.Node, tc: ts.TypeChecker): void {
switch (node.kind) {
// Handle: const { timestamp } = ...
case ts.SyntaxKind.BindingElement: {
const bindingElementNode = node as ts.BindingElement;
if (bindingElementNode.name.kind === ts.SyntaxKind.Identifier) {
handleBooleanNaming(bindingElementNode, tc, ctx);
}
break;
}
// Handle regular assignments: const block = ...
case ts.SyntaxKind.VariableDeclaration:
const variableDeclarationNode = node as ts.VariableDeclaration;
if (variableDeclarationNode.name.kind === ts.SyntaxKind.Identifier) {
handleBooleanNaming(node as ts.VariableDeclaration, tc, ctx);
}
break;
default:
_.noop();
}
}
function handleBooleanNaming(
node: ts.VariableDeclaration | ts.BindingElement,
tc: ts.TypeChecker,
ctx: Lint.WalkContext<void>,
): void {
const nodeName = node.name;
const variableName = nodeName.getText();
const lowercasedName = _.toLower(variableName);
const typeNode = tc.getTypeAtLocation(node);
const typeName = (typeNode as any).intrinsicName;
if (typeName === 'boolean') {
const hasProperName = !_.isUndefined(
_.find(VALID_BOOLEAN_PREFIXES, prefix => {
return _.startsWith(lowercasedName, prefix);
}),
);
if (!hasProperName) {
ctx.addFailureAtNode(node, Rule.FAILURE_STRING);
}
}
}
|