UNPKG

2.91 kBPlain TextView Raw
1import * as ts from 'typescript';
2import * as Lint from 'tslint';
3
4import { ErrorTolerantWalker } from './utils/ErrorTolerantWalker';
5import { ExtendedMetadata } from './utils/ExtendedMetadata';
6
7export const FAILURE_STRING: string = 'Flag (boolean) arguments are not allowed: ';
8
9/**
10 * Implementation of the newspaper-order rule.
11 */
12export class Rule extends Lint.Rules.AbstractRule {
13 public static metadata: ExtendedMetadata = {
14 ruleName: 'no-flag-args',
15 type: 'maintainability',
16 description:
17 'Passing a boolean into a function is a truly terrible practice. ' +
18 'It immediately complicates the signature of the method, loudly proclaiming that this function does more than one thing.',
19 options: null,
20 optionsDescription: '',
21 typescriptOnly: true,
22 issueClass: 'Non-SDL',
23 issueType: 'Warning',
24 severity: 'Important',
25 level: 'Opportunity for Excellence',
26 group: 'Correctness',
27 recommendation: 'true,',
28 commonWeaknessEnumeration: '',
29 };
30
31 public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
32 return this.applyWithWalker(new NoFlagArgsRuleWalker(sourceFile, this.getOptions()));
33 }
34}
35
36class NoFlagArgsRuleWalker extends ErrorTolerantWalker {
37 protected visitParameterDeclaration(node: ts.ParameterDeclaration): void {
38 if (this.isBooleanParameter(node) && !this.belongsToSetAssessor(node)) {
39 const failureMessage = this.makeFailureMessage(node, FAILURE_STRING);
40 this.addFailureAt(node.getStart(), node.getWidth(), failureMessage);
41 }
42 super.visitParameterDeclaration(node);
43 }
44
45 private isBooleanParameter(node: ts.ParameterDeclaration): boolean {
46 const { type } = node;
47 return type && type.kind === ts.SyntaxKind.BooleanKeyword;
48 }
49
50 private belongsToSetAssessor(node: ts.ParameterDeclaration): boolean {
51 const { parent } = node;
52 return parent && parent.kind === ts.SyntaxKind.SetAccessor;
53 }
54
55 private makeFailureMessage(node: ts.ParameterDeclaration, failureString: string): string {
56 const paramName = node.name.getText();
57 const pascalCaseParamName = this.toPascalCase(paramName);
58 const functionName: string | undefined = node.parent.name && node.parent.name.getText();
59 const recommendation = functionName
60 ? '\nSplit the function into two, such as ' +
61 `${functionName}When${pascalCaseParamName}` +
62 ' and ' +
63 `${functionName}WhenNot${pascalCaseParamName}.`
64 : '\nSplit the function into two.';
65 return failureString + paramName + recommendation;
66 }
67
68 private toPascalCase(str: string) {
69 if (typeof str !== 'string' || str.length === 0) {
70 return str;
71 }
72 return str[0].toUpperCase() + str.slice(1);
73 }
74}
75
\No newline at end of file