UNPKG

3.28 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 = 'Exceeds maximum function argument list length of ';
8export const FAILURE_RECOMMENDATION_STRING: string =
9 '\nConsider these two solutions for refactoring:\n' +
10 '1) Create a Class and pass common arguments into the constructor as instance properties. ' +
11 'Move this function to the new Class with a reduced arguments list.\n' +
12 '2) Instantiate an object containing each of the arguments and pass in the object instance as a single argument.';
13export const DEFAULT_MAX_ARGS_LENGTH: number = 3;
14
15/**
16 * Implementation of the newspaper-order rule.
17 */
18export class Rule extends Lint.Rules.AbstractRule {
19 public static metadata: ExtendedMetadata = {
20 ruleName: 'max-func-args',
21 type: 'maintainability',
22 description: 'The ideal number of arguments for a function is zero (niladic).',
23 options: null,
24 optionsDescription: '',
25 typescriptOnly: true,
26 issueClass: 'Non-SDL',
27 issueType: 'Warning',
28 severity: 'Important',
29 level: 'Opportunity for Excellence',
30 group: 'Correctness',
31 recommendation: '[true, 3],',
32 commonWeaknessEnumeration: '',
33 };
34
35 public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
36 return this.applyWithWalker(new MaxFunctionArgsRuleWalker(sourceFile, this.getOptions()));
37 }
38}
39
40class MaxFunctionArgsRuleWalker extends ErrorTolerantWalker {
41 private maxArgs: number = DEFAULT_MAX_ARGS_LENGTH;
42
43 constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) {
44 super(sourceFile, options);
45 this.parseOptions();
46 }
47
48 protected visitFunctionDeclaration(node: ts.FunctionDeclaration): void {
49 this.checkAndReport(node);
50 super.visitFunctionDeclaration(node);
51 }
52
53 protected visitArrowFunction(node: ts.ArrowFunction): void {
54 this.checkAndReport(node);
55 super.visitArrowFunction(node);
56 }
57
58 protected visitMethodDeclaration(node: ts.MethodDeclaration): void {
59 this.checkAndReport(node);
60 super.visitMethodDeclaration(node);
61 }
62
63 private checkAndReport(node: ts.SignatureDeclaration) {
64 if (node.parameters.length > this.maxArgs) {
65 const failureMessage = this.makeFailureMessage();
66 const { start, width } = this.getStartAndWidth(node.parameters);
67 this.addFailureAt(start, width, failureMessage);
68 }
69 }
70
71 private getStartAndWidth(nodes: ts.NodeArray<any>) {
72 const { pos, end } = nodes;
73 const start = pos;
74 const width = end - pos;
75 return {
76 start,
77 width,
78 };
79 }
80
81 private makeFailureMessage(): string {
82 return FAILURE_STRING + this.maxArgs + FAILURE_RECOMMENDATION_STRING;
83 }
84
85 private parseOptions(): void {
86 this.getOptions().forEach((opt: any) => {
87 if (typeof opt === 'boolean') {
88 return;
89 }
90 if (typeof opt === 'number') {
91 this.maxArgs = opt;
92 return;
93 }
94 });
95 }
96}