UNPKG

9.96 kBJavaScriptView Raw
1"use strict";
2var __extends = (this && this.__extends) || (function () {
3 var extendStatics = Object.setPrototypeOf ||
4 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6 return function (d, b) {
7 extendStatics(d, b);
8 function __() { this.constructor = d; }
9 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
10 };
11})();
12Object.defineProperty(exports, "__esModule", { value: true });
13var ts = require("typescript");
14var Lint = require("tslint");
15var AstUtils_1 = require("./utils/AstUtils");
16var Utils_1 = require("./utils/Utils");
17var tsutils_1 = require("tsutils");
18var Rule = (function (_super) {
19 __extends(Rule, _super);
20 function Rule() {
21 return _super !== null && _super.apply(this, arguments) || this;
22 }
23 Rule.prototype.apply = function (sourceFile) {
24 return this.applyWithWalker(new MaxFunctionBodyLengthRuleWalker(sourceFile, this.getOptions()));
25 };
26 Rule.metadata = {
27 ruleName: 'max-func-body-length',
28 type: 'maintainability',
29 description: 'Avoid long functions.',
30 options: null,
31 optionsDescription: '',
32 typescriptOnly: true,
33 issueClass: 'Non-SDL',
34 issueType: 'Warning',
35 severity: 'Moderate',
36 level: 'Opportunity for Excellence',
37 group: 'Clarity',
38 recommendation: '[true, 100, {"ignore-parameters-to-function-regex": "^describe$"}],',
39 commonWeaknessEnumeration: '398, 710'
40 };
41 return Rule;
42}(Lint.Rules.AbstractRule));
43exports.Rule = Rule;
44var FUNC_BODY_LENGTH = 'func-body-length';
45var FUNC_EXPRESSION_BODY_LENGTH = 'func-express-body-length';
46var ARROW_BODY_LENGTH = 'arrow-body-length';
47var METHOD_BODY_LENGTH = 'method-body-length';
48var CTOR_BODY_LENGTH = 'ctor-body-length';
49var IGNORE_PARAMETERS_TO_FUNCTION = 'ignore-parameters-to-function-regex';
50var IGNORE_COMMENTS = 'ignore-comments';
51var MaxFunctionBodyLengthRuleWalker = (function (_super) {
52 __extends(MaxFunctionBodyLengthRuleWalker, _super);
53 function MaxFunctionBodyLengthRuleWalker(sourceFile, options) {
54 var _this = _super.call(this, sourceFile, options) || this;
55 _this.ignoreNodes = [];
56 _this.parseOptions();
57 return _this;
58 }
59 MaxFunctionBodyLengthRuleWalker.prototype.visitCallExpression = function (node) {
60 var _this = this;
61 var functionName = AstUtils_1.AstUtils.getFunctionName(node);
62 if (this.ignoreParametersToFunctionRegex && this.ignoreParametersToFunctionRegex.test(functionName)) {
63 node.arguments.forEach(function (argument) {
64 _this.ignoreNodes.push(argument);
65 });
66 _super.prototype.visitCallExpression.call(this, node);
67 this.ignoreNodes = Utils_1.Utils.removeAll(this.ignoreNodes, node.arguments);
68 }
69 else {
70 _super.prototype.visitCallExpression.call(this, node);
71 }
72 };
73 MaxFunctionBodyLengthRuleWalker.prototype.visitArrowFunction = function (node) {
74 this.validate(node);
75 _super.prototype.visitArrowFunction.call(this, node);
76 };
77 MaxFunctionBodyLengthRuleWalker.prototype.visitMethodDeclaration = function (node) {
78 this.validate(node);
79 _super.prototype.visitMethodDeclaration.call(this, node);
80 };
81 MaxFunctionBodyLengthRuleWalker.prototype.visitFunctionDeclaration = function (node) {
82 this.validate(node);
83 _super.prototype.visitFunctionDeclaration.call(this, node);
84 };
85 MaxFunctionBodyLengthRuleWalker.prototype.visitFunctionExpression = function (node) {
86 this.validate(node);
87 _super.prototype.visitFunctionExpression.call(this, node);
88 };
89 MaxFunctionBodyLengthRuleWalker.prototype.visitConstructorDeclaration = function (node) {
90 this.validate(node);
91 _super.prototype.visitConstructorDeclaration.call(this, node);
92 };
93 MaxFunctionBodyLengthRuleWalker.prototype.visitClassDeclaration = function (node) {
94 this.currentClassName = node.name.text;
95 _super.prototype.visitClassDeclaration.call(this, node);
96 this.currentClassName = undefined;
97 };
98 MaxFunctionBodyLengthRuleWalker.prototype.validate = function (node) {
99 if (!Utils_1.Utils.contains(this.ignoreNodes, node)) {
100 var bodyLength = this.calcBodyLength(node);
101 if (this.ignoreComments) {
102 bodyLength -= this.calcBodyCommentLength(node);
103 }
104 if (this.isFunctionTooLong(node.kind, bodyLength)) {
105 this.addFuncBodyTooLongFailure(node, bodyLength);
106 }
107 }
108 };
109 MaxFunctionBodyLengthRuleWalker.prototype.calcBodyLength = function (node) {
110 if (node.body == null) {
111 return 0;
112 }
113 var sourceFile = this.getSourceFile();
114 var startLine = sourceFile.getLineAndCharacterOfPosition(node.body.pos).line;
115 var endLine = sourceFile.getLineAndCharacterOfPosition(node.body.end).line;
116 return endLine - startLine + 1;
117 };
118 MaxFunctionBodyLengthRuleWalker.prototype.calcBodyCommentLength = function (node) {
119 var commentLineCount = 0;
120 commentLineCount += node.getFullText()
121 .split(/\n/)
122 .filter(function (line) {
123 return line.trim().match(/^\/\//) !== null;
124 })
125 .length;
126 tsutils_1.forEachTokenWithTrivia(node, function (text, tokenSyntaxKind) {
127 if (tokenSyntaxKind === ts.SyntaxKind.MultiLineCommentTrivia) {
128 commentLineCount += text.split(/\n/).length;
129 }
130 });
131 return commentLineCount;
132 };
133 MaxFunctionBodyLengthRuleWalker.prototype.isFunctionTooLong = function (nodeKind, length) {
134 return length > this.getMaxLength(nodeKind);
135 };
136 MaxFunctionBodyLengthRuleWalker.prototype.parseOptions = function () {
137 var _this = this;
138 this.getOptions().forEach(function (opt) {
139 if (typeof (opt) === 'number') {
140 _this.maxBodyLength = opt;
141 return;
142 }
143 if (typeof (opt) === 'object') {
144 _this.maxFuncBodyLength = opt[FUNC_BODY_LENGTH];
145 _this.maxFuncExpressionBodyLength = opt[FUNC_EXPRESSION_BODY_LENGTH];
146 _this.maxArrowBodyLength = opt[ARROW_BODY_LENGTH];
147 _this.maxMethodBodyLength = opt[METHOD_BODY_LENGTH];
148 _this.maxCtorBodyLength = opt[CTOR_BODY_LENGTH];
149 _this.ignoreComments = opt[IGNORE_COMMENTS];
150 var regex = opt[IGNORE_PARAMETERS_TO_FUNCTION];
151 if (regex) {
152 _this.ignoreParametersToFunctionRegex = new RegExp(regex);
153 }
154 }
155 });
156 };
157 MaxFunctionBodyLengthRuleWalker.prototype.addFuncBodyTooLongFailure = function (node, length) {
158 this.addFailureAt(node.getStart(), node.getWidth(), this.formatFailureText(node, length));
159 };
160 MaxFunctionBodyLengthRuleWalker.prototype.formatFailureText = function (node, length) {
161 var funcTypeText = this.getFuncTypeText(node.kind);
162 var maxLength = this.getMaxLength(node.kind);
163 var placeText = this.formatPlaceText(node);
164 return "Max " + funcTypeText + " body length exceeded" + placeText + " - max: " + maxLength + ", actual: " + length;
165 };
166 MaxFunctionBodyLengthRuleWalker.prototype.formatPlaceText = function (node) {
167 var funcTypeText = this.getFuncTypeText(node.kind);
168 if (node.kind === ts.SyntaxKind.MethodDeclaration ||
169 node.kind === ts.SyntaxKind.FunctionDeclaration ||
170 node.kind === ts.SyntaxKind.FunctionExpression) {
171 return " in " + funcTypeText + " " + (node.name || { text: '' }).text + "()";
172 }
173 else if (node.kind === ts.SyntaxKind.Constructor) {
174 return " in class " + this.currentClassName;
175 }
176 return '';
177 };
178 MaxFunctionBodyLengthRuleWalker.prototype.getFuncTypeText = function (nodeKind) {
179 if (nodeKind === ts.SyntaxKind.FunctionDeclaration) {
180 return 'function';
181 }
182 else if (nodeKind === ts.SyntaxKind.FunctionExpression) {
183 return 'function expression';
184 }
185 else if (nodeKind === ts.SyntaxKind.MethodDeclaration) {
186 return 'method';
187 }
188 else if (nodeKind === ts.SyntaxKind.ArrowFunction) {
189 return 'arrow function';
190 }
191 else if (nodeKind === ts.SyntaxKind.Constructor) {
192 return 'constructor';
193 }
194 else {
195 throw new Error("Unsupported node kind: " + nodeKind);
196 }
197 };
198 MaxFunctionBodyLengthRuleWalker.prototype.getMaxLength = function (nodeKind) {
199 var result;
200 if (nodeKind === ts.SyntaxKind.FunctionDeclaration) {
201 result = this.maxFuncBodyLength;
202 }
203 else if (nodeKind === ts.SyntaxKind.FunctionExpression) {
204 result = this.maxFuncExpressionBodyLength;
205 }
206 else if (nodeKind === ts.SyntaxKind.MethodDeclaration) {
207 result = this.maxMethodBodyLength;
208 }
209 else if (nodeKind === ts.SyntaxKind.ArrowFunction) {
210 result = this.maxArrowBodyLength;
211 }
212 else if (nodeKind === ts.SyntaxKind.Constructor) {
213 result = this.maxCtorBodyLength;
214 }
215 else {
216 throw new Error("Unsupported node kind: " + nodeKind);
217 }
218 return result || this.maxBodyLength;
219 };
220 return MaxFunctionBodyLengthRuleWalker;
221}(Lint.RuleWalker));
222//# sourceMappingURL=maxFuncBodyLengthRule.js.map
\No newline at end of file