eslint 7.3.1 → 7.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -0
- package/README.md +28 -16
- package/lib/cli-engine/config-array-factory.js +1 -33
- package/lib/cli-engine/formatters/checkstyle.js +2 -2
- package/lib/linter/code-path-analysis/code-path-analyzer.js +38 -0
- package/lib/linter/code-path-analysis/code-path-segment.js +0 -1
- package/lib/linter/code-path-analysis/code-path-state.js +59 -0
- package/lib/linter/code-path-analysis/debug-helpers.js +26 -19
- package/lib/rule-tester/rule-tester.js +10 -0
- package/lib/rules/accessor-pairs.js +1 -14
- package/lib/rules/array-callback-return.js +26 -17
- package/lib/rules/arrow-body-style.js +43 -8
- package/lib/rules/arrow-parens.js +91 -108
- package/lib/rules/camelcase.js +47 -0
- package/lib/rules/comma-dangle.js +1 -2
- package/lib/rules/consistent-return.js +1 -12
- package/lib/rules/constructor-super.js +1 -0
- package/lib/rules/dot-location.js +20 -14
- package/lib/rules/dot-notation.js +36 -33
- package/lib/rules/func-call-spacing.js +42 -6
- package/lib/rules/func-name-matching.js +1 -4
- package/lib/rules/global-require.js +2 -1
- package/lib/rules/id-blacklist.js +14 -11
- package/lib/rules/id-denylist.js +230 -0
- package/lib/rules/indent.js +23 -3
- package/lib/rules/index.js +1 -0
- package/lib/rules/keyword-spacing.js +2 -2
- package/lib/rules/max-len.js +13 -2
- package/lib/rules/new-cap.js +10 -14
- package/lib/rules/newline-per-chained-call.js +15 -5
- package/lib/rules/no-alert.js +10 -3
- package/lib/rules/no-duplicate-case.js +23 -4
- package/lib/rules/no-eval.js +8 -38
- package/lib/rules/no-extend-native.js +37 -40
- package/lib/rules/no-extra-bind.js +57 -17
- package/lib/rules/no-extra-boolean-cast.js +7 -0
- package/lib/rules/no-extra-parens.js +48 -10
- package/lib/rules/no-implicit-coercion.js +11 -6
- package/lib/rules/no-implied-eval.js +7 -28
- package/lib/rules/no-import-assign.js +33 -32
- package/lib/rules/no-irregular-whitespace.js +22 -12
- package/lib/rules/no-magic-numbers.js +4 -8
- package/lib/rules/no-obj-calls.js +7 -4
- package/lib/rules/no-prototype-builtins.js +13 -3
- package/lib/rules/no-self-assign.js +3 -53
- package/lib/rules/no-setter-return.js +5 -8
- package/lib/rules/no-underscore-dangle.js +66 -21
- package/lib/rules/no-unexpected-multiline.js +2 -2
- package/lib/rules/no-unneeded-ternary.js +0 -2
- package/lib/rules/no-unused-expressions.js +55 -23
- package/lib/rules/no-useless-call.js +10 -7
- package/lib/rules/no-whitespace-before-property.js +16 -4
- package/lib/rules/object-curly-newline.js +4 -4
- package/lib/rules/operator-assignment.js +3 -42
- package/lib/rules/padding-line-between-statements.js +2 -2
- package/lib/rules/prefer-arrow-callback.js +90 -25
- package/lib/rules/prefer-exponentiation-operator.js +1 -1
- package/lib/rules/prefer-numeric-literals.js +4 -13
- package/lib/rules/prefer-promise-reject-errors.js +1 -3
- package/lib/rules/prefer-regex-literals.js +68 -13
- package/lib/rules/prefer-spread.js +2 -6
- package/lib/rules/radix.js +5 -2
- package/lib/rules/sort-imports.js +28 -0
- package/lib/rules/use-isnan.js +1 -1
- package/lib/rules/utils/ast-utils.js +317 -153
- package/lib/rules/wrap-iife.js +9 -2
- package/lib/rules/yoda.js +2 -55
- package/messages/extend-config-missing.txt +1 -1
- package/messages/no-config-found.txt +1 -1
- package/messages/plugin-conflict.txt +1 -1
- package/messages/plugin-missing.txt +1 -1
- package/messages/whitespace-found.txt +1 -1
- package/package.json +6 -7
@@ -9,16 +9,12 @@
|
|
9
9
|
// Helpers
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
|
-
const { findVariable
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
]),
|
19
|
-
Reflect: new Set([
|
20
|
-
"defineProperty", "deleteProperty", "set", "setPrototypeOf"
|
21
|
-
])
|
12
|
+
const { findVariable } = require("eslint-utils");
|
13
|
+
const astUtils = require("./utils/ast-utils");
|
14
|
+
|
15
|
+
const WellKnownMutationFunctions = {
|
16
|
+
Object: /^(?:assign|definePropert(?:y|ies)|freeze|setPrototypeOf)$/u,
|
17
|
+
Reflect: /^(?:(?:define|delete)Property|set(?:PrototypeOf)?)$/u
|
22
18
|
};
|
23
19
|
|
24
20
|
/**
|
@@ -56,17 +52,20 @@ function isAssignmentLeft(node) {
|
|
56
52
|
* @returns {boolean} `true` if the node is the operand of mutation unary operator.
|
57
53
|
*/
|
58
54
|
function isOperandOfMutationUnaryOperator(node) {
|
59
|
-
const
|
55
|
+
const argumentNode = node.parent.type === "ChainExpression"
|
56
|
+
? node.parent
|
57
|
+
: node;
|
58
|
+
const { parent } = argumentNode;
|
60
59
|
|
61
60
|
return (
|
62
61
|
(
|
63
62
|
parent.type === "UpdateExpression" &&
|
64
|
-
parent.argument ===
|
63
|
+
parent.argument === argumentNode
|
65
64
|
) ||
|
66
65
|
(
|
67
66
|
parent.type === "UnaryExpression" &&
|
68
67
|
parent.operator === "delete" &&
|
69
|
-
parent.argument ===
|
68
|
+
parent.argument === argumentNode
|
70
69
|
)
|
71
70
|
);
|
72
71
|
}
|
@@ -92,35 +91,37 @@ function isIterationVariable(node) {
|
|
92
91
|
}
|
93
92
|
|
94
93
|
/**
|
95
|
-
* Check if a given node is the
|
94
|
+
* Check if a given node is at the first argument of a well-known mutation function.
|
95
|
+
* - `Object.assign`
|
96
|
+
* - `Object.defineProperty`
|
97
|
+
* - `Object.defineProperties`
|
98
|
+
* - `Object.freeze`
|
99
|
+
* - `Object.setPrototypeOf`
|
100
|
+
* - `Refrect.defineProperty`
|
101
|
+
* - `Refrect.deleteProperty`
|
102
|
+
* - `Refrect.set`
|
103
|
+
* - `Refrect.setPrototypeOf`
|
96
104
|
* @param {ASTNode} node The node to check.
|
97
105
|
* @param {Scope} scope A `escope.Scope` object to find variable (whichever).
|
98
|
-
* @returns {boolean} `true` if the node is the
|
106
|
+
* @returns {boolean} `true` if the node is at the first argument of a well-known mutation function.
|
99
107
|
*/
|
100
108
|
function isArgumentOfWellKnownMutationFunction(node, scope) {
|
101
109
|
const { parent } = node;
|
102
110
|
|
111
|
+
if (parent.type !== "CallExpression" || parent.arguments[0] !== node) {
|
112
|
+
return false;
|
113
|
+
}
|
114
|
+
const callee = astUtils.skipChainExpression(parent.callee);
|
115
|
+
|
103
116
|
if (
|
104
|
-
|
105
|
-
|
106
|
-
parent.callee.type === "MemberExpression" &&
|
107
|
-
parent.callee.object.type === "Identifier"
|
117
|
+
!astUtils.isSpecificMemberAccess(callee, "Object", WellKnownMutationFunctions.Object) &&
|
118
|
+
!astUtils.isSpecificMemberAccess(callee, "Reflect", WellKnownMutationFunctions.Reflect)
|
108
119
|
) {
|
109
|
-
|
110
|
-
const { object } = callee;
|
111
|
-
|
112
|
-
if (Object.keys(MutationMethods).includes(object.name)) {
|
113
|
-
const variable = findVariable(scope, object);
|
114
|
-
|
115
|
-
return (
|
116
|
-
variable !== null &&
|
117
|
-
variable.scope.type === "global" &&
|
118
|
-
MutationMethods[object.name].has(getPropertyName(callee, scope))
|
119
|
-
);
|
120
|
-
}
|
120
|
+
return false;
|
121
121
|
}
|
122
|
+
const variable = findVariable(scope, callee.object);
|
122
123
|
|
123
|
-
return
|
124
|
+
return variable !== null && variable.scope.type === "global";
|
124
125
|
}
|
125
126
|
|
126
127
|
/**
|
@@ -91,7 +91,7 @@ module.exports = {
|
|
91
91
|
const locStart = node.loc.start;
|
92
92
|
const locEnd = node.loc.end;
|
93
93
|
|
94
|
-
errors = errors.filter(({ loc: errorLoc }) => {
|
94
|
+
errors = errors.filter(({ loc: { start: errorLoc } }) => {
|
95
95
|
if (errorLoc.line >= locStart.line && errorLoc.line <= locEnd.line) {
|
96
96
|
if (errorLoc.column >= locStart.column && (errorLoc.column <= locEnd.column || errorLoc.line < locEnd.line)) {
|
97
97
|
return false;
|
@@ -160,15 +160,19 @@ module.exports = {
|
|
160
160
|
let match;
|
161
161
|
|
162
162
|
while ((match = IRREGULAR_WHITESPACE.exec(sourceLine)) !== null) {
|
163
|
-
const location = {
|
164
|
-
line: lineNumber,
|
165
|
-
column: match.index
|
166
|
-
};
|
167
|
-
|
168
163
|
errors.push({
|
169
164
|
node,
|
170
165
|
messageId: "noIrregularWhitespace",
|
171
|
-
loc:
|
166
|
+
loc: {
|
167
|
+
start: {
|
168
|
+
line: lineNumber,
|
169
|
+
column: match.index
|
170
|
+
},
|
171
|
+
end: {
|
172
|
+
line: lineNumber,
|
173
|
+
column: match.index + match[0].length
|
174
|
+
}
|
175
|
+
}
|
172
176
|
});
|
173
177
|
}
|
174
178
|
});
|
@@ -189,16 +193,22 @@ module.exports = {
|
|
189
193
|
|
190
194
|
while ((match = IRREGULAR_LINE_TERMINATORS.exec(source)) !== null) {
|
191
195
|
const lineIndex = linebreaks.indexOf(match[0], lastLineIndex + 1) || 0;
|
192
|
-
const location = {
|
193
|
-
line: lineIndex + 1,
|
194
|
-
column: sourceLines[lineIndex].length
|
195
|
-
};
|
196
196
|
|
197
197
|
errors.push({
|
198
198
|
node,
|
199
199
|
messageId: "noIrregularWhitespace",
|
200
|
-
loc:
|
200
|
+
loc: {
|
201
|
+
start: {
|
202
|
+
line: lineIndex + 1,
|
203
|
+
column: sourceLines[lineIndex].length
|
204
|
+
},
|
205
|
+
end: {
|
206
|
+
line: lineIndex + 2,
|
207
|
+
column: 0
|
208
|
+
}
|
209
|
+
}
|
201
210
|
});
|
211
|
+
|
202
212
|
lastLineIndex = lineIndex;
|
203
213
|
}
|
204
214
|
}
|
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
-
const
|
8
|
+
const astUtils = require("./utils/ast-utils");
|
9
9
|
|
10
10
|
// Maximum array length by the ECMAScript Specification.
|
11
11
|
const MAX_ARRAY_LENGTH = 2 ** 32 - 1;
|
@@ -100,12 +100,8 @@ module.exports = {
|
|
100
100
|
|
101
101
|
return parent.type === "CallExpression" && fullNumberNode === parent.arguments[1] &&
|
102
102
|
(
|
103
|
-
parent.callee
|
104
|
-
(
|
105
|
-
parent.callee.type === "MemberExpression" &&
|
106
|
-
parent.callee.object.name === "Number" &&
|
107
|
-
parent.callee.property.name === "parseInt"
|
108
|
-
)
|
103
|
+
astUtils.isSpecificId(parent.callee, "parseInt") ||
|
104
|
+
astUtils.isSpecificMemberAccess(parent.callee, "Number", "parseInt")
|
109
105
|
);
|
110
106
|
}
|
111
107
|
|
@@ -157,7 +153,7 @@ module.exports = {
|
|
157
153
|
|
158
154
|
return {
|
159
155
|
Literal(node) {
|
160
|
-
if (!isNumericLiteral(node)) {
|
156
|
+
if (!astUtils.isNumericLiteral(node)) {
|
161
157
|
return;
|
162
158
|
}
|
163
159
|
|
@@ -24,10 +24,13 @@ const nonCallableGlobals = ["Atomics", "JSON", "Math", "Reflect"];
|
|
24
24
|
* @returns {string} name to report
|
25
25
|
*/
|
26
26
|
function getReportNodeName(node) {
|
27
|
-
if (node.
|
28
|
-
return
|
27
|
+
if (node.type === "ChainExpression") {
|
28
|
+
return getReportNodeName(node.expression);
|
29
29
|
}
|
30
|
-
|
30
|
+
if (node.type === "MemberExpression") {
|
31
|
+
return getPropertyName(node);
|
32
|
+
}
|
33
|
+
return node.name;
|
31
34
|
}
|
32
35
|
|
33
36
|
//------------------------------------------------------------------------------
|
@@ -69,7 +72,7 @@ module.exports = {
|
|
69
72
|
}
|
70
73
|
|
71
74
|
for (const { node, path } of tracker.iterateGlobalReferences(traceMap)) {
|
72
|
-
const name = getReportNodeName(node);
|
75
|
+
const name = getReportNodeName(node.callee);
|
73
76
|
const ref = path[0];
|
74
77
|
const messageId = name === ref ? "unexpectedCall" : "unexpectedRefCall";
|
75
78
|
|
@@ -4,6 +4,12 @@
|
|
4
4
|
*/
|
5
5
|
"use strict";
|
6
6
|
|
7
|
+
//------------------------------------------------------------------------------
|
8
|
+
// Requirements
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
const astUtils = require("./utils/ast-utils");
|
12
|
+
|
7
13
|
//------------------------------------------------------------------------------
|
8
14
|
// Rule Definition
|
9
15
|
//------------------------------------------------------------------------------
|
@@ -39,15 +45,19 @@ module.exports = {
|
|
39
45
|
* @returns {void}
|
40
46
|
*/
|
41
47
|
function disallowBuiltIns(node) {
|
42
|
-
|
48
|
+
|
49
|
+
// TODO: just use `astUtils.getStaticPropertyName(node.callee)`
|
50
|
+
const callee = astUtils.skipChainExpression(node.callee);
|
51
|
+
|
52
|
+
if (callee.type !== "MemberExpression" || callee.computed) {
|
43
53
|
return;
|
44
54
|
}
|
45
|
-
const propName =
|
55
|
+
const propName = callee.property.name;
|
46
56
|
|
47
57
|
if (DISALLOWED_PROPS.indexOf(propName) > -1) {
|
48
58
|
context.report({
|
49
59
|
messageId: "prototypeBuildIn",
|
50
|
-
loc:
|
60
|
+
loc: callee.property.loc,
|
51
61
|
data: { prop: propName },
|
52
62
|
node
|
53
63
|
});
|
@@ -17,56 +17,6 @@ const astUtils = require("./utils/ast-utils");
|
|
17
17
|
|
18
18
|
const SPACES = /\s+/gu;
|
19
19
|
|
20
|
-
/**
|
21
|
-
* Checks whether the property of 2 given member expression nodes are the same
|
22
|
-
* property or not.
|
23
|
-
* @param {ASTNode} left A member expression node to check.
|
24
|
-
* @param {ASTNode} right Another member expression node to check.
|
25
|
-
* @returns {boolean} `true` if the member expressions have the same property.
|
26
|
-
*/
|
27
|
-
function isSameProperty(left, right) {
|
28
|
-
if (left.property.type === "Identifier" &&
|
29
|
-
left.property.type === right.property.type &&
|
30
|
-
left.property.name === right.property.name &&
|
31
|
-
left.computed === right.computed
|
32
|
-
) {
|
33
|
-
return true;
|
34
|
-
}
|
35
|
-
|
36
|
-
const lname = astUtils.getStaticPropertyName(left);
|
37
|
-
const rname = astUtils.getStaticPropertyName(right);
|
38
|
-
|
39
|
-
return lname !== null && lname === rname;
|
40
|
-
}
|
41
|
-
|
42
|
-
/**
|
43
|
-
* Checks whether 2 given member expression nodes are the reference to the same
|
44
|
-
* property or not.
|
45
|
-
* @param {ASTNode} left A member expression node to check.
|
46
|
-
* @param {ASTNode} right Another member expression node to check.
|
47
|
-
* @returns {boolean} `true` if the member expressions are the reference to the
|
48
|
-
* same property or not.
|
49
|
-
*/
|
50
|
-
function isSameMember(left, right) {
|
51
|
-
if (!isSameProperty(left, right)) {
|
52
|
-
return false;
|
53
|
-
}
|
54
|
-
|
55
|
-
const lobj = left.object;
|
56
|
-
const robj = right.object;
|
57
|
-
|
58
|
-
if (lobj.type !== robj.type) {
|
59
|
-
return false;
|
60
|
-
}
|
61
|
-
if (lobj.type === "MemberExpression") {
|
62
|
-
return isSameMember(lobj, robj);
|
63
|
-
}
|
64
|
-
if (lobj.type === "ThisExpression") {
|
65
|
-
return true;
|
66
|
-
}
|
67
|
-
return lobj.type === "Identifier" && lobj.name === robj.name;
|
68
|
-
}
|
69
|
-
|
70
20
|
/**
|
71
21
|
* Traverses 2 Pattern nodes in parallel, then reports self-assignments.
|
72
22
|
* @param {ASTNode|null} left A left node to traverse. This is a Pattern or
|
@@ -162,9 +112,9 @@ function eachSelfAssignment(left, right, props, report) {
|
|
162
112
|
}
|
163
113
|
} else if (
|
164
114
|
props &&
|
165
|
-
left.type === "MemberExpression" &&
|
166
|
-
right.type === "MemberExpression" &&
|
167
|
-
|
115
|
+
astUtils.skipChainExpression(left).type === "MemberExpression" &&
|
116
|
+
astUtils.skipChainExpression(right).type === "MemberExpression" &&
|
117
|
+
astUtils.isSameReference(left, right)
|
168
118
|
) {
|
169
119
|
report(right);
|
170
120
|
}
|
@@ -39,15 +39,12 @@ function isGlobalReference(node, scope) {
|
|
39
39
|
* @returns {boolean} `true` if the node is argument at the given position.
|
40
40
|
*/
|
41
41
|
function isArgumentOfGlobalMethodCall(node, scope, objectName, methodName, index) {
|
42
|
-
const
|
42
|
+
const callNode = node.parent;
|
43
43
|
|
44
|
-
return
|
45
|
-
|
46
|
-
|
47
|
-
astUtils.
|
48
|
-
parent.callee.object.type === "Identifier" &&
|
49
|
-
parent.callee.object.name === objectName &&
|
50
|
-
isGlobalReference(parent.callee.object, scope);
|
44
|
+
return callNode.type === "CallExpression" &&
|
45
|
+
callNode.arguments[index] === node &&
|
46
|
+
astUtils.isSpecificMemberAccess(callNode.callee, objectName, methodName) &&
|
47
|
+
isGlobalReference(astUtils.skipChainExpression(callNode.callee).object, scope);
|
51
48
|
}
|
52
49
|
|
53
50
|
/**
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @fileoverview Rule to flag
|
2
|
+
* @fileoverview Rule to flag dangling underscores in variable declarations.
|
3
3
|
* @author Matt DuVall <http://www.mattduvall.com>
|
4
4
|
*/
|
5
5
|
|
@@ -45,6 +45,10 @@ module.exports = {
|
|
45
45
|
enforceInMethodNames: {
|
46
46
|
type: "boolean",
|
47
47
|
default: false
|
48
|
+
},
|
49
|
+
allowFunctionParams: {
|
50
|
+
type: "boolean",
|
51
|
+
default: true
|
48
52
|
}
|
49
53
|
},
|
50
54
|
additionalProperties: false
|
@@ -64,6 +68,7 @@ module.exports = {
|
|
64
68
|
const allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false;
|
65
69
|
const allowAfterThisConstructor = typeof options.allowAfterThisConstructor !== "undefined" ? options.allowAfterThisConstructor : false;
|
66
70
|
const enforceInMethodNames = typeof options.enforceInMethodNames !== "undefined" ? options.enforceInMethodNames : false;
|
71
|
+
const allowFunctionParams = typeof options.allowFunctionParams !== "undefined" ? options.allowFunctionParams : true;
|
67
72
|
|
68
73
|
//-------------------------------------------------------------------------
|
69
74
|
// Helpers
|
@@ -80,12 +85,12 @@ module.exports = {
|
|
80
85
|
}
|
81
86
|
|
82
87
|
/**
|
83
|
-
* Check if identifier has a underscore
|
88
|
+
* Check if identifier has a dangling underscore
|
84
89
|
* @param {string} identifier name of the node
|
85
90
|
* @returns {boolean} true if its is present
|
86
91
|
* @private
|
87
92
|
*/
|
88
|
-
function
|
93
|
+
function hasDanglingUnderscore(identifier) {
|
89
94
|
const len = identifier.length;
|
90
95
|
|
91
96
|
return identifier !== "_" && (identifier[0] === "_" || identifier[len - 1] === "_");
|
@@ -126,16 +131,53 @@ module.exports = {
|
|
126
131
|
}
|
127
132
|
|
128
133
|
/**
|
129
|
-
* Check if function has a underscore
|
134
|
+
* Check if function parameter has a dangling underscore.
|
135
|
+
* @param {ASTNode} node function node to evaluate
|
136
|
+
* @returns {void}
|
137
|
+
* @private
|
138
|
+
*/
|
139
|
+
function checkForDanglingUnderscoreInFunctionParameters(node) {
|
140
|
+
if (!allowFunctionParams) {
|
141
|
+
node.params.forEach(param => {
|
142
|
+
const { type } = param;
|
143
|
+
let nodeToCheck;
|
144
|
+
|
145
|
+
if (type === "RestElement") {
|
146
|
+
nodeToCheck = param.argument;
|
147
|
+
} else if (type === "AssignmentPattern") {
|
148
|
+
nodeToCheck = param.left;
|
149
|
+
} else {
|
150
|
+
nodeToCheck = param;
|
151
|
+
}
|
152
|
+
|
153
|
+
if (nodeToCheck.type === "Identifier") {
|
154
|
+
const identifier = nodeToCheck.name;
|
155
|
+
|
156
|
+
if (hasDanglingUnderscore(identifier) && !isAllowed(identifier)) {
|
157
|
+
context.report({
|
158
|
+
node: param,
|
159
|
+
messageId: "unexpectedUnderscore",
|
160
|
+
data: {
|
161
|
+
identifier
|
162
|
+
}
|
163
|
+
});
|
164
|
+
}
|
165
|
+
}
|
166
|
+
});
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
/**
|
171
|
+
* Check if function has a dangling underscore
|
130
172
|
* @param {ASTNode} node node to evaluate
|
131
173
|
* @returns {void}
|
132
174
|
* @private
|
133
175
|
*/
|
134
|
-
function
|
135
|
-
if (node.id) {
|
176
|
+
function checkForDanglingUnderscoreInFunction(node) {
|
177
|
+
if (node.type === "FunctionDeclaration" && node.id) {
|
136
178
|
const identifier = node.id.name;
|
137
179
|
|
138
|
-
if (typeof identifier !== "undefined" &&
|
180
|
+
if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) && !isAllowed(identifier)) {
|
139
181
|
context.report({
|
140
182
|
node,
|
141
183
|
messageId: "unexpectedUnderscore",
|
@@ -145,18 +187,19 @@ module.exports = {
|
|
145
187
|
});
|
146
188
|
}
|
147
189
|
}
|
190
|
+
checkForDanglingUnderscoreInFunctionParameters(node);
|
148
191
|
}
|
149
192
|
|
150
193
|
/**
|
151
|
-
* Check if variable expression has a underscore
|
194
|
+
* Check if variable expression has a dangling underscore
|
152
195
|
* @param {ASTNode} node node to evaluate
|
153
196
|
* @returns {void}
|
154
197
|
* @private
|
155
198
|
*/
|
156
|
-
function
|
199
|
+
function checkForDanglingUnderscoreInVariableExpression(node) {
|
157
200
|
const identifier = node.id.name;
|
158
201
|
|
159
|
-
if (typeof identifier !== "undefined" &&
|
202
|
+
if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
|
160
203
|
!isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) {
|
161
204
|
context.report({
|
162
205
|
node,
|
@@ -169,18 +212,18 @@ module.exports = {
|
|
169
212
|
}
|
170
213
|
|
171
214
|
/**
|
172
|
-
* Check if member expression has a underscore
|
215
|
+
* Check if member expression has a dangling underscore
|
173
216
|
* @param {ASTNode} node node to evaluate
|
174
217
|
* @returns {void}
|
175
218
|
* @private
|
176
219
|
*/
|
177
|
-
function
|
220
|
+
function checkForDanglingUnderscoreInMemberExpression(node) {
|
178
221
|
const identifier = node.property.name,
|
179
222
|
isMemberOfThis = node.object.type === "ThisExpression",
|
180
223
|
isMemberOfSuper = node.object.type === "Super",
|
181
224
|
isMemberOfThisConstructor = isThisConstructorReference(node);
|
182
225
|
|
183
|
-
if (typeof identifier !== "undefined" &&
|
226
|
+
if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
|
184
227
|
!(isMemberOfThis && allowAfterThis) &&
|
185
228
|
!(isMemberOfSuper && allowAfterSuper) &&
|
186
229
|
!(isMemberOfThisConstructor && allowAfterThisConstructor) &&
|
@@ -196,16 +239,16 @@ module.exports = {
|
|
196
239
|
}
|
197
240
|
|
198
241
|
/**
|
199
|
-
* Check if method declaration or method property has a underscore
|
242
|
+
* Check if method declaration or method property has a dangling underscore
|
200
243
|
* @param {ASTNode} node node to evaluate
|
201
244
|
* @returns {void}
|
202
245
|
* @private
|
203
246
|
*/
|
204
|
-
function
|
247
|
+
function checkForDanglingUnderscoreInMethod(node) {
|
205
248
|
const identifier = node.key.name;
|
206
249
|
const isMethod = node.type === "MethodDefinition" || node.type === "Property" && node.method;
|
207
250
|
|
208
|
-
if (typeof identifier !== "undefined" && enforceInMethodNames && isMethod &&
|
251
|
+
if (typeof identifier !== "undefined" && enforceInMethodNames && isMethod && hasDanglingUnderscore(identifier) && !isAllowed(identifier)) {
|
209
252
|
context.report({
|
210
253
|
node,
|
211
254
|
messageId: "unexpectedUnderscore",
|
@@ -221,11 +264,13 @@ module.exports = {
|
|
221
264
|
//--------------------------------------------------------------------------
|
222
265
|
|
223
266
|
return {
|
224
|
-
FunctionDeclaration:
|
225
|
-
VariableDeclarator:
|
226
|
-
MemberExpression:
|
227
|
-
MethodDefinition:
|
228
|
-
Property:
|
267
|
+
FunctionDeclaration: checkForDanglingUnderscoreInFunction,
|
268
|
+
VariableDeclarator: checkForDanglingUnderscoreInVariableExpression,
|
269
|
+
MemberExpression: checkForDanglingUnderscoreInMemberExpression,
|
270
|
+
MethodDefinition: checkForDanglingUnderscoreInMethod,
|
271
|
+
Property: checkForDanglingUnderscoreInMethod,
|
272
|
+
FunctionExpression: checkForDanglingUnderscoreInFunction,
|
273
|
+
ArrowFunctionExpression: checkForDanglingUnderscoreInFunction
|
229
274
|
};
|
230
275
|
|
231
276
|
}
|
@@ -68,7 +68,7 @@ module.exports = {
|
|
68
68
|
return {
|
69
69
|
|
70
70
|
MemberExpression(node) {
|
71
|
-
if (!node.computed) {
|
71
|
+
if (!node.computed || node.optional) {
|
72
72
|
return;
|
73
73
|
}
|
74
74
|
checkForBreakAfter(node.object, "property");
|
@@ -96,7 +96,7 @@ module.exports = {
|
|
96
96
|
},
|
97
97
|
|
98
98
|
CallExpression(node) {
|
99
|
-
if (node.arguments.length === 0) {
|
99
|
+
if (node.arguments.length === 0 || node.optional) {
|
100
100
|
return;
|
101
101
|
}
|
102
102
|
checkForBreakAfter(node.callee, "function");
|
@@ -122,7 +122,6 @@ module.exports = {
|
|
122
122
|
if (isBooleanLiteral(node.alternate) && isBooleanLiteral(node.consequent)) {
|
123
123
|
context.report({
|
124
124
|
node,
|
125
|
-
loc: node.consequent.loc.start,
|
126
125
|
messageId: "unnecessaryConditionalExpression",
|
127
126
|
fix(fixer) {
|
128
127
|
if (node.consequent.value === node.alternate.value) {
|
@@ -144,7 +143,6 @@ module.exports = {
|
|
144
143
|
} else if (!defaultAssignment && matchesDefaultAssignment(node)) {
|
145
144
|
context.report({
|
146
145
|
node,
|
147
|
-
loc: node.consequent.loc.start,
|
148
146
|
messageId: "unnecessaryConditionalAssignment",
|
149
147
|
fix: fixer => {
|
150
148
|
const shouldParenthesizeAlternate =
|
@@ -8,6 +8,22 @@
|
|
8
8
|
// Rule Definition
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
|
+
/**
|
12
|
+
* Returns `true`.
|
13
|
+
* @returns {boolean} `true`.
|
14
|
+
*/
|
15
|
+
function alwaysTrue() {
|
16
|
+
return true;
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Returns `false`.
|
21
|
+
* @returns {boolean} `false`.
|
22
|
+
*/
|
23
|
+
function alwaysFalse() {
|
24
|
+
return false;
|
25
|
+
}
|
26
|
+
|
11
27
|
module.exports = {
|
12
28
|
meta: {
|
13
29
|
type: "suggestion",
|
@@ -101,40 +117,56 @@ module.exports = {
|
|
101
117
|
}
|
102
118
|
|
103
119
|
/**
|
104
|
-
*
|
105
|
-
*
|
106
|
-
* @returns {boolean} whether the given node is a valid expression
|
120
|
+
* The member functions return `true` if the type has no side-effects.
|
121
|
+
* Unknown nodes are handled as `false`, then this rule ignores those.
|
107
122
|
*/
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
123
|
+
const Checker = Object.assign(Object.create(null), {
|
124
|
+
isDisallowed(node) {
|
125
|
+
return (Checker[node.type] || alwaysFalse)(node);
|
126
|
+
},
|
127
|
+
|
128
|
+
ArrayExpression: alwaysTrue,
|
129
|
+
ArrowFunctionExpression: alwaysTrue,
|
130
|
+
BinaryExpression: alwaysTrue,
|
131
|
+
ChainExpression(node) {
|
132
|
+
return Checker.isDisallowed(node.expression);
|
133
|
+
},
|
134
|
+
ClassExpression: alwaysTrue,
|
135
|
+
ConditionalExpression(node) {
|
136
|
+
if (allowTernary) {
|
137
|
+
return Checker.isDisallowed(node.consequent) || Checker.isDisallowed(node.alternate);
|
114
138
|
}
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
139
|
+
return true;
|
140
|
+
},
|
141
|
+
FunctionExpression: alwaysTrue,
|
142
|
+
Identifier: alwaysTrue,
|
143
|
+
Literal: alwaysTrue,
|
144
|
+
LogicalExpression(node) {
|
145
|
+
if (allowShortCircuit) {
|
146
|
+
return Checker.isDisallowed(node.right);
|
120
147
|
}
|
121
|
-
}
|
122
|
-
|
123
|
-
if (allowTaggedTemplates && node.type === "TaggedTemplateExpression") {
|
124
148
|
return true;
|
149
|
+
},
|
150
|
+
MemberExpression: alwaysTrue,
|
151
|
+
MetaProperty: alwaysTrue,
|
152
|
+
ObjectExpression: alwaysTrue,
|
153
|
+
SequenceExpression: alwaysTrue,
|
154
|
+
TaggedTemplateExpression() {
|
155
|
+
return !allowTaggedTemplates;
|
156
|
+
},
|
157
|
+
TemplateLiteral: alwaysTrue,
|
158
|
+
ThisExpression: alwaysTrue,
|
159
|
+
UnaryExpression(node) {
|
160
|
+
return node.operator !== "void" && node.operator !== "delete";
|
125
161
|
}
|
126
|
-
|
127
|
-
return /^(?:Assignment|Call|New|Update|Yield|Await|Import)Expression$/u.test(node.type) ||
|
128
|
-
(node.type === "UnaryExpression" && ["delete", "void"].indexOf(node.operator) >= 0);
|
129
|
-
}
|
162
|
+
});
|
130
163
|
|
131
164
|
return {
|
132
165
|
ExpressionStatement(node) {
|
133
|
-
if (
|
166
|
+
if (Checker.isDisallowed(node.expression) && !isDirective(node, context.getAncestors())) {
|
134
167
|
context.report({ node, messageId: "unusedExpression" });
|
135
168
|
}
|
136
169
|
}
|
137
170
|
};
|
138
|
-
|
139
171
|
}
|
140
172
|
};
|