UNPKG

8.75 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 ErrorTolerantWalker_1 = require("./utils/ErrorTolerantWalker");
16var AstUtils_1 = require("./utils/AstUtils");
17var Rule = (function (_super) {
18 __extends(Rule, _super);
19 function Rule() {
20 return _super !== null && _super.apply(this, arguments) || this;
21 }
22 Rule.prototype.apply = function (sourceFile) {
23 return this.applyWithWalker(new NoUnnecessaryBindRuleWalker(sourceFile, this.getOptions()));
24 };
25 Rule.metadata = {
26 ruleName: 'no-unnecessary-bind',
27 type: 'maintainability',
28 description: 'Do not bind `this` as the context for a function literal or lambda expression.',
29 options: null,
30 optionsDescription: '',
31 typescriptOnly: true,
32 issueClass: 'Non-SDL',
33 issueType: 'Warning',
34 severity: 'Important',
35 level: 'Opportunity for Excellence',
36 group: 'Correctness',
37 commonWeaknessEnumeration: '398, 710'
38 };
39 Rule.FAILURE_FUNCTION_WITH_BIND = 'Binding function literal with \'this\' context. Use lambdas instead';
40 Rule.FAILURE_ARROW_WITH_BIND = 'Binding lambda with \'this\' context. Lambdas already have \'this\' bound';
41 Rule.UNDERSCORE_BINARY_FUNCTION_NAMES = [
42 'all', 'any', 'collect', 'countBy', 'detect', 'each',
43 'every', 'filter', 'find', 'forEach', 'groupBy', 'indexBy',
44 'map', 'max', 'max', 'min', 'partition', 'reject',
45 'select', 'some', 'sortBy', 'times', 'uniq', 'unique'
46 ];
47 Rule.UNDERSCORE_TERNARY_FUNCTION_NAMES = [
48 'foldl', 'foldr', 'inject', 'reduce', 'reduceRight'
49 ];
50 return Rule;
51}(Lint.Rules.AbstractRule));
52exports.Rule = Rule;
53var NoUnnecessaryBindRuleWalker = (function (_super) {
54 __extends(NoUnnecessaryBindRuleWalker, _super);
55 function NoUnnecessaryBindRuleWalker() {
56 return _super !== null && _super.apply(this, arguments) || this;
57 }
58 NoUnnecessaryBindRuleWalker.prototype.visitCallExpression = function (node) {
59 var _this = this;
60 var analyzers = [
61 new TypeScriptFunctionAnalyzer(), new UnderscoreStaticAnalyzer(), new UnderscoreInstanceAnalyzer()
62 ];
63 analyzers.forEach(function (analyzer) {
64 if (analyzer.canHandle(node)) {
65 var contextArgument = analyzer.getContextArgument(node);
66 var functionArgument = analyzer.getFunctionArgument(node);
67 if (contextArgument == null || functionArgument == null) {
68 return;
69 }
70 if (contextArgument.getText() === 'this') {
71 if (isArrowFunction(functionArgument)) {
72 _this.addFailureAt(node.getStart(), node.getWidth(), Rule.FAILURE_ARROW_WITH_BIND);
73 }
74 else if (isFunctionLiteral(functionArgument)) {
75 _this.addFailureAt(node.getStart(), node.getWidth(), Rule.FAILURE_FUNCTION_WITH_BIND);
76 }
77 }
78 }
79 });
80 _super.prototype.visitCallExpression.call(this, node);
81 };
82 return NoUnnecessaryBindRuleWalker;
83}(ErrorTolerantWalker_1.ErrorTolerantWalker));
84var TypeScriptFunctionAnalyzer = (function () {
85 function TypeScriptFunctionAnalyzer() {
86 }
87 TypeScriptFunctionAnalyzer.prototype.canHandle = function (node) {
88 return !!(AstUtils_1.AstUtils.getFunctionName(node) === 'bind'
89 && node.arguments.length === 1
90 && node.expression.kind === ts.SyntaxKind.PropertyAccessExpression);
91 };
92 TypeScriptFunctionAnalyzer.prototype.getContextArgument = function (node) {
93 return node.arguments[0];
94 };
95 TypeScriptFunctionAnalyzer.prototype.getFunctionArgument = function (node) {
96 return node.expression.expression;
97 };
98 return TypeScriptFunctionAnalyzer;
99}());
100var UnderscoreStaticAnalyzer = (function () {
101 function UnderscoreStaticAnalyzer() {
102 }
103 UnderscoreStaticAnalyzer.prototype.canHandle = function (node) {
104 var isUnderscore = AstUtils_1.AstUtils.getFunctionTarget(node) === '_';
105 if (isUnderscore) {
106 var functionName = AstUtils_1.AstUtils.getFunctionName(node);
107 if (functionName === 'bind') {
108 return node.arguments.length === 2;
109 }
110 }
111 return isUnderscore;
112 };
113 UnderscoreStaticAnalyzer.prototype.getContextArgument = function (node) {
114 var functionName = AstUtils_1.AstUtils.getFunctionName(node);
115 if (Rule.UNDERSCORE_BINARY_FUNCTION_NAMES.indexOf(functionName) !== -1) {
116 return node.arguments[2];
117 }
118 else if (Rule.UNDERSCORE_TERNARY_FUNCTION_NAMES.indexOf(functionName) !== -1) {
119 return node.arguments[3];
120 }
121 else if (functionName === 'sortedIndex') {
122 return node.arguments[3];
123 }
124 else if (functionName === 'bind') {
125 return node.arguments[1];
126 }
127 return null;
128 };
129 UnderscoreStaticAnalyzer.prototype.getFunctionArgument = function (node) {
130 var functionName = AstUtils_1.AstUtils.getFunctionName(node);
131 if (Rule.UNDERSCORE_BINARY_FUNCTION_NAMES.indexOf(functionName) !== -1) {
132 return node.arguments[1];
133 }
134 else if (Rule.UNDERSCORE_TERNARY_FUNCTION_NAMES.indexOf(functionName) !== -1) {
135 return node.arguments[1];
136 }
137 else if (functionName === 'sortedIndex') {
138 return node.arguments[2];
139 }
140 else if (functionName === 'bind') {
141 return node.arguments[0];
142 }
143 return null;
144 };
145 return UnderscoreStaticAnalyzer;
146}());
147var UnderscoreInstanceAnalyzer = (function () {
148 function UnderscoreInstanceAnalyzer() {
149 }
150 UnderscoreInstanceAnalyzer.prototype.canHandle = function (node) {
151 if (node.expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
152 var propExpression = node.expression;
153 if (propExpression.expression.kind === ts.SyntaxKind.CallExpression) {
154 var call = propExpression.expression;
155 return call.expression.getText() === '_';
156 }
157 }
158 return false;
159 };
160 UnderscoreInstanceAnalyzer.prototype.getContextArgument = function (node) {
161 var functionName = AstUtils_1.AstUtils.getFunctionName(node);
162 if (Rule.UNDERSCORE_BINARY_FUNCTION_NAMES.indexOf(functionName) !== -1) {
163 return node.arguments[1];
164 }
165 else if (Rule.UNDERSCORE_TERNARY_FUNCTION_NAMES.indexOf(functionName) !== -1) {
166 return node.arguments[2];
167 }
168 else if (functionName === 'sortedIndex') {
169 return node.arguments[2];
170 }
171 return null;
172 };
173 UnderscoreInstanceAnalyzer.prototype.getFunctionArgument = function (node) {
174 var functionName = AstUtils_1.AstUtils.getFunctionName(node);
175 if (Rule.UNDERSCORE_BINARY_FUNCTION_NAMES.indexOf(functionName) !== -1) {
176 return node.arguments[0];
177 }
178 else if (Rule.UNDERSCORE_TERNARY_FUNCTION_NAMES.indexOf(functionName) !== -1) {
179 return node.arguments[0];
180 }
181 else if (functionName === 'sortedIndex') {
182 return node.arguments[1];
183 }
184 return null;
185 };
186 return UnderscoreInstanceAnalyzer;
187}());
188function isFunctionLiteral(expression) {
189 if (expression.kind === ts.SyntaxKind.FunctionExpression) {
190 return true;
191 }
192 if (expression.kind === ts.SyntaxKind.ParenthesizedExpression) {
193 return isFunctionLiteral(expression.expression);
194 }
195 return false;
196}
197function isArrowFunction(expression) {
198 if (expression.kind === ts.SyntaxKind.ArrowFunction) {
199 return true;
200 }
201 if (expression.kind === ts.SyntaxKind.ParenthesizedExpression) {
202 return isArrowFunction(expression.expression);
203 }
204 return false;
205}
206//# sourceMappingURL=noUnnecessaryBindRule.js.map
\No newline at end of file