eslint 8.14.0 → 8.17.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/README.md +17 -12
- package/bin/eslint.js +1 -1
- package/lib/cli-engine/cli-engine.js +2 -4
- package/lib/cli-engine/lint-result-cache.js +1 -1
- package/lib/eslint/eslint.js +3 -3
- package/lib/linter/code-path-analysis/code-path-segment.js +1 -1
- package/lib/linter/code-path-analysis/code-path-state.js +1 -1
- package/lib/linter/code-path-analysis/code-path.js +1 -1
- package/lib/rules/accessor-pairs.js +4 -4
- package/lib/rules/callback-return.js +2 -2
- package/lib/rules/capitalized-comments.js +1 -1
- package/lib/rules/consistent-this.js +1 -1
- package/lib/rules/dot-notation.js +2 -2
- package/lib/rules/function-paren-newline.js +8 -5
- package/lib/rules/global-require.js +3 -3
- package/lib/rules/indent-legacy.js +2 -2
- package/lib/rules/indent.js +45 -13
- package/lib/rules/jsx-quotes.js +1 -1
- package/lib/rules/lines-around-comment.js +3 -3
- package/lib/rules/max-lines.js +2 -2
- package/lib/rules/max-statements.js +1 -1
- package/lib/rules/newline-before-return.js +1 -1
- package/lib/rules/no-bitwise.js +2 -2
- package/lib/rules/no-console.js +1 -1
- package/lib/rules/no-constant-binary-expression.js +3 -3
- package/lib/rules/no-control-regex.js +23 -10
- package/lib/rules/no-empty-function.js +1 -1
- package/lib/rules/no-extra-boolean-cast.js +3 -3
- package/lib/rules/no-extra-semi.js +1 -1
- package/lib/rules/no-global-assign.js +1 -1
- package/lib/rules/no-implicit-coercion.js +8 -8
- package/lib/rules/no-loop-func.js +1 -1
- package/lib/rules/no-magic-numbers.js +3 -3
- package/lib/rules/no-misleading-character-class.js +90 -17
- package/lib/rules/no-mixed-operators.js +1 -1
- package/lib/rules/no-mixed-requires.js +1 -1
- package/lib/rules/no-multi-spaces.js +1 -1
- package/lib/rules/no-native-reassign.js +1 -1
- package/lib/rules/no-new-object.js +1 -1
- package/lib/rules/no-new-wrappers.js +1 -1
- package/lib/rules/no-octal.js +2 -2
- package/lib/rules/no-prototype-builtins.js +3 -3
- package/lib/rules/no-shadow.js +5 -5
- package/lib/rules/no-sparse-arrays.js +1 -1
- package/lib/rules/no-underscore-dangle.js +31 -2
- package/lib/rules/no-unused-expressions.js +1 -1
- package/lib/rules/no-unused-vars.js +1 -1
- package/lib/rules/no-use-before-define.js +15 -2
- package/lib/rules/operator-assignment.js +2 -2
- package/lib/rules/prefer-const.js +1 -1
- package/lib/rules/prefer-reflect.js +2 -2
- package/lib/rules/prefer-regex-literals.js +3 -3
- package/lib/rules/quote-props.js +2 -2
- package/lib/rules/quotes.js +1 -1
- package/lib/rules/spaced-comment.js +1 -1
- package/lib/rules/valid-jsdoc.js +1 -1
- package/lib/rules/valid-typeof.js +4 -4
- package/lib/rules/yoda.js +1 -1
- package/lib/shared/types.js +1 -1
- package/package.json +25 -8
@@ -78,7 +78,7 @@ module.exports = {
|
|
78
78
|
* @returns {void}
|
79
79
|
*/
|
80
80
|
function checkVariable(variable) {
|
81
|
-
if (variable.writeable === false && exceptions.
|
81
|
+
if (variable.writeable === false && !exceptions.includes(variable.name)) {
|
82
82
|
variable.references.forEach(checkReference);
|
83
83
|
}
|
84
84
|
}
|
@@ -30,9 +30,9 @@ function parseOptions(options) {
|
|
30
30
|
}
|
31
31
|
|
32
32
|
/**
|
33
|
-
* Checks whether or not a node is a double logical
|
33
|
+
* Checks whether or not a node is a double logical negating.
|
34
34
|
* @param {ASTNode} node An UnaryExpression node to check.
|
35
|
-
* @returns {boolean} Whether or not the node is a double logical
|
35
|
+
* @returns {boolean} Whether or not the node is a double logical negating.
|
36
36
|
*/
|
37
37
|
function isDoubleLogicalNegating(node) {
|
38
38
|
return (
|
@@ -257,7 +257,7 @@ module.exports = {
|
|
257
257
|
let operatorAllowed;
|
258
258
|
|
259
259
|
// !!foo
|
260
|
-
operatorAllowed = options.allow.
|
260
|
+
operatorAllowed = options.allow.includes("!!");
|
261
261
|
if (!operatorAllowed && options.boolean && isDoubleLogicalNegating(node)) {
|
262
262
|
const recommendation = `Boolean(${sourceCode.getText(node.argument.argument)})`;
|
263
263
|
|
@@ -265,7 +265,7 @@ module.exports = {
|
|
265
265
|
}
|
266
266
|
|
267
267
|
// ~foo.indexOf(bar)
|
268
|
-
operatorAllowed = options.allow.
|
268
|
+
operatorAllowed = options.allow.includes("~");
|
269
269
|
if (!operatorAllowed && options.boolean && isBinaryNegatingOfIndexOf(node)) {
|
270
270
|
|
271
271
|
// `foo?.indexOf(bar) !== -1` will be true (== found) if the `foo` is nullish. So use `>= 0` in that case.
|
@@ -276,7 +276,7 @@ module.exports = {
|
|
276
276
|
}
|
277
277
|
|
278
278
|
// +foo
|
279
|
-
operatorAllowed = options.allow.
|
279
|
+
operatorAllowed = options.allow.includes("+");
|
280
280
|
if (!operatorAllowed && options.number && node.operator === "+" && !isNumeric(node.argument)) {
|
281
281
|
const recommendation = `Number(${sourceCode.getText(node.argument)})`;
|
282
282
|
|
@@ -289,7 +289,7 @@ module.exports = {
|
|
289
289
|
let operatorAllowed;
|
290
290
|
|
291
291
|
// 1 * foo
|
292
|
-
operatorAllowed = options.allow.
|
292
|
+
operatorAllowed = options.allow.includes("*");
|
293
293
|
const nonNumericOperand = !operatorAllowed && options.number && isMultiplyByOne(node) && getNonNumericOperand(node);
|
294
294
|
|
295
295
|
if (nonNumericOperand) {
|
@@ -299,7 +299,7 @@ module.exports = {
|
|
299
299
|
}
|
300
300
|
|
301
301
|
// "" + foo
|
302
|
-
operatorAllowed = options.allow.
|
302
|
+
operatorAllowed = options.allow.includes("+");
|
303
303
|
if (!operatorAllowed && options.string && isConcatWithEmptyString(node)) {
|
304
304
|
const recommendation = `String(${sourceCode.getText(getNonEmptyOperand(node))})`;
|
305
305
|
|
@@ -310,7 +310,7 @@ module.exports = {
|
|
310
310
|
AssignmentExpression(node) {
|
311
311
|
|
312
312
|
// foo += ""
|
313
|
-
const operatorAllowed = options.allow.
|
313
|
+
const operatorAllowed = options.allow.includes("+");
|
314
314
|
|
315
315
|
if (!operatorAllowed && options.string && isAppendEmptyString(node)) {
|
316
316
|
const code = sourceCode.getText(getNonEmptyOperand(node));
|
@@ -125,7 +125,7 @@ function isSafe(loopNode, reference) {
|
|
125
125
|
* The reference is every reference of the upper scope's variable we are
|
126
126
|
* looking now.
|
127
127
|
*
|
128
|
-
* It's
|
128
|
+
* It's safe if the reference matches one of the following condition.
|
129
129
|
* - is readonly.
|
130
130
|
* - doesn't exist inside a local function and after the border.
|
131
131
|
* @param {eslint-scope.Reference} upperRef A reference to check.
|
@@ -80,7 +80,7 @@ module.exports = {
|
|
80
80
|
const config = context.options[0] || {},
|
81
81
|
detectObjects = !!config.detectObjects,
|
82
82
|
enforceConst = !!config.enforceConst,
|
83
|
-
ignore = (config.ignore || []).map(normalizeIgnoreValue),
|
83
|
+
ignore = new Set((config.ignore || []).map(normalizeIgnoreValue)),
|
84
84
|
ignoreArrayIndexes = !!config.ignoreArrayIndexes,
|
85
85
|
ignoreDefaultValues = !!config.ignoreDefaultValues;
|
86
86
|
|
@@ -92,7 +92,7 @@ module.exports = {
|
|
92
92
|
* @returns {boolean} true if the value is ignored
|
93
93
|
*/
|
94
94
|
function isIgnoredValue(value) {
|
95
|
-
return ignore.
|
95
|
+
return ignore.has(value);
|
96
96
|
}
|
97
97
|
|
98
98
|
/**
|
@@ -209,7 +209,7 @@ module.exports = {
|
|
209
209
|
});
|
210
210
|
}
|
211
211
|
} else if (
|
212
|
-
okTypes.
|
212
|
+
!okTypes.includes(parent.type) ||
|
213
213
|
(parent.type === "AssignmentExpression" && parent.left.type === "Identifier")
|
214
214
|
) {
|
215
215
|
context.report({
|
@@ -4,13 +4,16 @@
|
|
4
4
|
"use strict";
|
5
5
|
|
6
6
|
const { CALL, CONSTRUCT, ReferenceTracker, getStringIfConstant } = require("eslint-utils");
|
7
|
-
const { RegExpParser, visitRegExpAST } = require("regexpp");
|
7
|
+
const { RegExpValidator, RegExpParser, visitRegExpAST } = require("regexpp");
|
8
8
|
const { isCombiningCharacter, isEmojiModifier, isRegionalIndicatorSymbol, isSurrogatePair } = require("./utils/unicode");
|
9
|
+
const astUtils = require("./utils/ast-utils.js");
|
9
10
|
|
10
11
|
//------------------------------------------------------------------------------
|
11
12
|
// Helpers
|
12
13
|
//------------------------------------------------------------------------------
|
13
14
|
|
15
|
+
const REGEXPP_LATEST_ECMA_VERSION = 2022;
|
16
|
+
|
14
17
|
/**
|
15
18
|
* Iterate character sequences of a given nodes.
|
16
19
|
*
|
@@ -109,6 +112,8 @@ module.exports = {
|
|
109
112
|
url: "https://eslint.org/docs/rules/no-misleading-character-class"
|
110
113
|
},
|
111
114
|
|
115
|
+
hasSuggestions: true,
|
116
|
+
|
112
117
|
schema: [],
|
113
118
|
|
114
119
|
messages: {
|
@@ -116,10 +121,12 @@ module.exports = {
|
|
116
121
|
combiningClass: "Unexpected combined character in character class.",
|
117
122
|
emojiModifier: "Unexpected modified Emoji in character class.",
|
118
123
|
regionalIndicatorSymbol: "Unexpected national flag in character class.",
|
119
|
-
zwj: "Unexpected joined character sequence in character class."
|
124
|
+
zwj: "Unexpected joined character sequence in character class.",
|
125
|
+
suggestUnicodeFlag: "Add unicode 'u' flag to regex."
|
120
126
|
}
|
121
127
|
},
|
122
128
|
create(context) {
|
129
|
+
const sourceCode = context.getSourceCode();
|
123
130
|
const parser = new RegExpParser();
|
124
131
|
|
125
132
|
/**
|
@@ -127,17 +134,10 @@ module.exports = {
|
|
127
134
|
* @param {Node} node The node to report.
|
128
135
|
* @param {string} pattern The regular expression pattern to verify.
|
129
136
|
* @param {string} flags The flags of the regular expression.
|
137
|
+
* @param {Function} unicodeFixer Fixer for missing "u" flag.
|
130
138
|
* @returns {void}
|
131
139
|
*/
|
132
|
-
function verify(node, pattern, flags) {
|
133
|
-
const has = {
|
134
|
-
surrogatePairWithoutUFlag: false,
|
135
|
-
combiningClass: false,
|
136
|
-
variationSelector: false,
|
137
|
-
emojiModifier: false,
|
138
|
-
regionalIndicatorSymbol: false,
|
139
|
-
zwj: false
|
140
|
-
};
|
140
|
+
function verify(node, pattern, flags, unicodeFixer) {
|
141
141
|
let patternNode;
|
142
142
|
|
143
143
|
try {
|
@@ -153,26 +153,75 @@ module.exports = {
|
|
153
153
|
return;
|
154
154
|
}
|
155
155
|
|
156
|
+
const foundKinds = new Set();
|
157
|
+
|
156
158
|
visitRegExpAST(patternNode, {
|
157
159
|
onCharacterClassEnter(ccNode) {
|
158
160
|
for (const chars of iterateCharacterSequence(ccNode.elements)) {
|
159
161
|
for (const kind of kinds) {
|
160
|
-
|
162
|
+
if (hasCharacterSequence[kind](chars)) {
|
163
|
+
foundKinds.add(kind);
|
164
|
+
}
|
161
165
|
}
|
162
166
|
}
|
163
167
|
}
|
164
168
|
});
|
165
169
|
|
166
|
-
for (const kind of
|
167
|
-
|
168
|
-
|
170
|
+
for (const kind of foundKinds) {
|
171
|
+
let suggest;
|
172
|
+
|
173
|
+
if (kind === "surrogatePairWithoutUFlag") {
|
174
|
+
suggest = [{
|
175
|
+
messageId: "suggestUnicodeFlag",
|
176
|
+
fix: unicodeFixer
|
177
|
+
}];
|
169
178
|
}
|
179
|
+
|
180
|
+
context.report({
|
181
|
+
node,
|
182
|
+
messageId: kind,
|
183
|
+
suggest
|
184
|
+
});
|
170
185
|
}
|
171
186
|
}
|
172
187
|
|
188
|
+
/**
|
189
|
+
* Checks if the given regular expression pattern would be valid with the `u` flag.
|
190
|
+
* @param {string} pattern The regular expression pattern to verify.
|
191
|
+
* @returns {boolean} `true` if the pattern would be valid with the `u` flag.
|
192
|
+
* `false` if the pattern would be invalid with the `u` flag or the configured
|
193
|
+
* ecmaVersion doesn't support the `u` flag.
|
194
|
+
*/
|
195
|
+
function isValidWithUnicodeFlag(pattern) {
|
196
|
+
const { ecmaVersion } = context.parserOptions;
|
197
|
+
|
198
|
+
// ecmaVersion is unknown or it doesn't support the 'u' flag
|
199
|
+
if (typeof ecmaVersion !== "number" || ecmaVersion <= 5) {
|
200
|
+
return false;
|
201
|
+
}
|
202
|
+
|
203
|
+
const validator = new RegExpValidator({
|
204
|
+
ecmaVersion: Math.min(ecmaVersion + 2009, REGEXPP_LATEST_ECMA_VERSION)
|
205
|
+
});
|
206
|
+
|
207
|
+
try {
|
208
|
+
validator.validatePattern(pattern, void 0, void 0, /* uFlag = */ true);
|
209
|
+
} catch {
|
210
|
+
return false;
|
211
|
+
}
|
212
|
+
|
213
|
+
return true;
|
214
|
+
}
|
215
|
+
|
173
216
|
return {
|
174
217
|
"Literal[regex]"(node) {
|
175
|
-
verify(node, node.regex.pattern, node.regex.flags
|
218
|
+
verify(node, node.regex.pattern, node.regex.flags, fixer => {
|
219
|
+
if (!isValidWithUnicodeFlag(node.regex.pattern)) {
|
220
|
+
return null;
|
221
|
+
}
|
222
|
+
|
223
|
+
return fixer.insertTextAfter(node, "u");
|
224
|
+
});
|
176
225
|
},
|
177
226
|
"Program"() {
|
178
227
|
const scope = context.getScope();
|
@@ -191,7 +240,31 @@ module.exports = {
|
|
191
240
|
const flags = getStringIfConstant(flagsNode, scope);
|
192
241
|
|
193
242
|
if (typeof pattern === "string") {
|
194
|
-
verify(node, pattern, flags || ""
|
243
|
+
verify(node, pattern, flags || "", fixer => {
|
244
|
+
|
245
|
+
if (!isValidWithUnicodeFlag(pattern)) {
|
246
|
+
return null;
|
247
|
+
}
|
248
|
+
|
249
|
+
if (node.arguments.length === 1) {
|
250
|
+
const penultimateToken = sourceCode.getLastToken(node, { skip: 1 }); // skip closing parenthesis
|
251
|
+
|
252
|
+
return fixer.insertTextAfter(
|
253
|
+
penultimateToken,
|
254
|
+
astUtils.isCommaToken(penultimateToken)
|
255
|
+
? ' "u",'
|
256
|
+
: ', "u"'
|
257
|
+
);
|
258
|
+
}
|
259
|
+
|
260
|
+
if ((flagsNode.type === "Literal" && typeof flagsNode.value === "string") || flagsNode.type === "TemplateLiteral") {
|
261
|
+
const range = [flagsNode.range[0], flagsNode.range[1] - 1];
|
262
|
+
|
263
|
+
return fixer.insertTextAfterRange(range, "u");
|
264
|
+
}
|
265
|
+
|
266
|
+
return null;
|
267
|
+
});
|
195
268
|
}
|
196
269
|
}
|
197
270
|
}
|
@@ -64,7 +64,7 @@ function normalizeOptions(options = {}) {
|
|
64
64
|
* @returns {boolean} `true` if such group existed.
|
65
65
|
*/
|
66
66
|
function includesBothInAGroup(groups, left, right) {
|
67
|
-
return groups.some(group => group.
|
67
|
+
return groups.some(group => group.includes(left) && group.includes(right));
|
68
68
|
}
|
69
69
|
|
70
70
|
/**
|
@@ -56,7 +56,7 @@ module.exports = {
|
|
56
56
|
const options = context.options[0] || {};
|
57
57
|
const ignoreEOLComments = options.ignoreEOLComments;
|
58
58
|
const exceptions = Object.assign({ Property: true }, options.exceptions);
|
59
|
-
const hasExceptions = Object.keys(exceptions).
|
59
|
+
const hasExceptions = Object.keys(exceptions).some(key => exceptions[key]);
|
60
60
|
|
61
61
|
/**
|
62
62
|
* Formats value of given comment token for error message by truncating its length.
|
@@ -81,7 +81,7 @@ module.exports = {
|
|
81
81
|
* @returns {void}
|
82
82
|
*/
|
83
83
|
function checkVariable(variable) {
|
84
|
-
if (variable.writeable === false && exceptions.
|
84
|
+
if (variable.writeable === false && !exceptions.includes(variable.name)) {
|
85
85
|
variable.references.forEach(checkReference);
|
86
86
|
}
|
87
87
|
}
|
@@ -34,7 +34,7 @@ module.exports = {
|
|
34
34
|
NewExpression(node) {
|
35
35
|
const wrapperObjects = ["String", "Number", "Boolean"];
|
36
36
|
|
37
|
-
if (wrapperObjects.
|
37
|
+
if (wrapperObjects.includes(node.callee.name)) {
|
38
38
|
context.report({
|
39
39
|
node,
|
40
40
|
messageId: "noConstructor",
|
package/lib/rules/no-octal.js
CHANGED
@@ -23,7 +23,7 @@ module.exports = {
|
|
23
23
|
schema: [],
|
24
24
|
|
25
25
|
messages: {
|
26
|
-
|
26
|
+
noOctal: "Octal literals should not be used."
|
27
27
|
}
|
28
28
|
},
|
29
29
|
|
@@ -35,7 +35,7 @@ module.exports = {
|
|
35
35
|
if (typeof node.value === "number" && /^0[0-9]/u.test(node.raw)) {
|
36
36
|
context.report({
|
37
37
|
node,
|
38
|
-
messageId: "
|
38
|
+
messageId: "noOctal"
|
39
39
|
});
|
40
40
|
}
|
41
41
|
}
|
@@ -33,11 +33,11 @@ module.exports = {
|
|
33
33
|
},
|
34
34
|
|
35
35
|
create(context) {
|
36
|
-
const DISALLOWED_PROPS = [
|
36
|
+
const DISALLOWED_PROPS = new Set([
|
37
37
|
"hasOwnProperty",
|
38
38
|
"isPrototypeOf",
|
39
39
|
"propertyIsEnumerable"
|
40
|
-
];
|
40
|
+
]);
|
41
41
|
|
42
42
|
/**
|
43
43
|
* Reports if a disallowed property is used in a CallExpression
|
@@ -54,7 +54,7 @@ module.exports = {
|
|
54
54
|
|
55
55
|
const propName = astUtils.getStaticPropertyName(callee);
|
56
56
|
|
57
|
-
if (propName !== null && DISALLOWED_PROPS.
|
57
|
+
if (propName !== null && DISALLOWED_PROPS.has(propName)) {
|
58
58
|
context.report({
|
59
59
|
messageId: "prototypeBuildIn",
|
60
60
|
loc: callee.property.loc,
|
package/lib/rules/no-shadow.js
CHANGED
@@ -15,8 +15,8 @@ const astUtils = require("./utils/ast-utils");
|
|
15
15
|
// Helpers
|
16
16
|
//------------------------------------------------------------------------------
|
17
17
|
|
18
|
-
const FUNC_EXPR_NODE_TYPES = ["ArrowFunctionExpression", "FunctionExpression"];
|
19
|
-
const CALL_EXPR_NODE_TYPE = ["CallExpression"];
|
18
|
+
const FUNC_EXPR_NODE_TYPES = new Set(["ArrowFunctionExpression", "FunctionExpression"]);
|
19
|
+
const CALL_EXPR_NODE_TYPE = new Set(["CallExpression"]);
|
20
20
|
const FOR_IN_OF_TYPE = /^For(?:In|Of)Statement$/u;
|
21
21
|
const SENTINEL_TYPE = /^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/u;
|
22
22
|
|
@@ -123,7 +123,7 @@ module.exports = {
|
|
123
123
|
const { variableScope } = variable.scope;
|
124
124
|
|
125
125
|
|
126
|
-
if (!(FUNC_EXPR_NODE_TYPES.
|
126
|
+
if (!(FUNC_EXPR_NODE_TYPES.has(variableScope.block.type) && getOuterScope(variableScope) === shadowedVariable.scope)) {
|
127
127
|
return false;
|
128
128
|
}
|
129
129
|
|
@@ -132,7 +132,7 @@ module.exports = {
|
|
132
132
|
|
133
133
|
const callExpression = findSelfOrAncestor(
|
134
134
|
parent,
|
135
|
-
node => CALL_EXPR_NODE_TYPE.
|
135
|
+
node => CALL_EXPR_NODE_TYPE.has(node.type)
|
136
136
|
);
|
137
137
|
|
138
138
|
if (!callExpression) {
|
@@ -173,7 +173,7 @@ module.exports = {
|
|
173
173
|
* @returns {boolean} Whether or not the variable name is allowed.
|
174
174
|
*/
|
175
175
|
function isAllowed(variable) {
|
176
|
-
return options.allow.
|
176
|
+
return options.allow.includes(variable.name);
|
177
177
|
}
|
178
178
|
|
179
179
|
/**
|
@@ -49,6 +49,10 @@ module.exports = {
|
|
49
49
|
allowFunctionParams: {
|
50
50
|
type: "boolean",
|
51
51
|
default: true
|
52
|
+
},
|
53
|
+
enforceInClassFields: {
|
54
|
+
type: "boolean",
|
55
|
+
default: false
|
52
56
|
}
|
53
57
|
},
|
54
58
|
additionalProperties: false
|
@@ -68,6 +72,7 @@ module.exports = {
|
|
68
72
|
const allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false;
|
69
73
|
const allowAfterThisConstructor = typeof options.allowAfterThisConstructor !== "undefined" ? options.allowAfterThisConstructor : false;
|
70
74
|
const enforceInMethodNames = typeof options.enforceInMethodNames !== "undefined" ? options.enforceInMethodNames : false;
|
75
|
+
const enforceInClassFields = typeof options.enforceInClassFields !== "undefined" ? options.enforceInClassFields : false;
|
71
76
|
const allowFunctionParams = typeof options.allowFunctionParams !== "undefined" ? options.allowFunctionParams : true;
|
72
77
|
|
73
78
|
//-------------------------------------------------------------------------
|
@@ -81,7 +86,7 @@ module.exports = {
|
|
81
86
|
* @private
|
82
87
|
*/
|
83
88
|
function isAllowed(identifier) {
|
84
|
-
return ALLOWED_VARIABLES.
|
89
|
+
return ALLOWED_VARIABLES.includes(identifier);
|
85
90
|
}
|
86
91
|
|
87
92
|
/**
|
@@ -261,6 +266,30 @@ module.exports = {
|
|
261
266
|
}
|
262
267
|
}
|
263
268
|
|
269
|
+
/**
|
270
|
+
* Check if a class field has a dangling underscore
|
271
|
+
* @param {ASTNode} node node to evaluate
|
272
|
+
* @returns {void}
|
273
|
+
* @private
|
274
|
+
*/
|
275
|
+
function checkForDanglingUnderscoreInClassField(node) {
|
276
|
+
const identifier = node.key.name;
|
277
|
+
|
278
|
+
if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
|
279
|
+
enforceInClassFields &&
|
280
|
+
!isAllowed(identifier)) {
|
281
|
+
context.report({
|
282
|
+
node,
|
283
|
+
messageId: "unexpectedUnderscore",
|
284
|
+
data: {
|
285
|
+
identifier: node.key.type === "PrivateIdentifier"
|
286
|
+
? `#${identifier}`
|
287
|
+
: identifier
|
288
|
+
}
|
289
|
+
});
|
290
|
+
}
|
291
|
+
}
|
292
|
+
|
264
293
|
//--------------------------------------------------------------------------
|
265
294
|
// Public API
|
266
295
|
//--------------------------------------------------------------------------
|
@@ -270,7 +299,7 @@ module.exports = {
|
|
270
299
|
VariableDeclarator: checkForDanglingUnderscoreInVariableExpression,
|
271
300
|
MemberExpression: checkForDanglingUnderscoreInMemberExpression,
|
272
301
|
MethodDefinition: checkForDanglingUnderscoreInMethod,
|
273
|
-
PropertyDefinition:
|
302
|
+
PropertyDefinition: checkForDanglingUnderscoreInClassField,
|
274
303
|
Property: checkForDanglingUnderscoreInMethod,
|
275
304
|
FunctionExpression: checkForDanglingUnderscoreInFunction,
|
276
305
|
ArrowFunctionExpression: checkForDanglingUnderscoreInFunction
|
@@ -21,6 +21,7 @@ function parseOptions(options) {
|
|
21
21
|
let functions = true;
|
22
22
|
let classes = true;
|
23
23
|
let variables = true;
|
24
|
+
let allowNamedExports = false;
|
24
25
|
|
25
26
|
if (typeof options === "string") {
|
26
27
|
functions = (options !== "nofunc");
|
@@ -28,9 +29,10 @@ function parseOptions(options) {
|
|
28
29
|
functions = options.functions !== false;
|
29
30
|
classes = options.classes !== false;
|
30
31
|
variables = options.variables !== false;
|
32
|
+
allowNamedExports = !!options.allowNamedExports;
|
31
33
|
}
|
32
34
|
|
33
|
-
return { functions, classes, variables };
|
35
|
+
return { functions, classes, variables, allowNamedExports };
|
34
36
|
}
|
35
37
|
|
36
38
|
/**
|
@@ -240,7 +242,8 @@ module.exports = {
|
|
240
242
|
properties: {
|
241
243
|
functions: { type: "boolean" },
|
242
244
|
classes: { type: "boolean" },
|
243
|
-
variables: { type: "boolean" }
|
245
|
+
variables: { type: "boolean" },
|
246
|
+
allowNamedExports: { type: "boolean" }
|
244
247
|
},
|
245
248
|
additionalProperties: false
|
246
249
|
}
|
@@ -273,6 +276,16 @@ module.exports = {
|
|
273
276
|
return false;
|
274
277
|
}
|
275
278
|
|
279
|
+
const { identifier } = reference;
|
280
|
+
|
281
|
+
if (
|
282
|
+
options.allowNamedExports &&
|
283
|
+
identifier.parent.type === "ExportSpecifier" &&
|
284
|
+
identifier.parent.local === identifier
|
285
|
+
) {
|
286
|
+
return false;
|
287
|
+
}
|
288
|
+
|
276
289
|
const variable = reference.resolved;
|
277
290
|
|
278
291
|
if (!variable || variable.defs.length === 0) {
|
@@ -22,7 +22,7 @@ const astUtils = require("./utils/ast-utils");
|
|
22
22
|
* shorthand form.
|
23
23
|
*/
|
24
24
|
function isCommutativeOperatorWithShorthand(operator) {
|
25
|
-
return ["*", "&", "^", "|"].
|
25
|
+
return ["*", "&", "^", "|"].includes(operator);
|
26
26
|
}
|
27
27
|
|
28
28
|
/**
|
@@ -33,7 +33,7 @@ function isCommutativeOperatorWithShorthand(operator) {
|
|
33
33
|
* a shorthand form.
|
34
34
|
*/
|
35
35
|
function isNonCommutativeOperatorWithShorthand(operator) {
|
36
|
-
return ["+", "-", "/", "%", "<<", ">>", ">>>", "**"].
|
36
|
+
return ["+", "-", "/", "%", "<<", ">>", ">>>", "**"].includes(operator);
|
37
37
|
}
|
38
38
|
|
39
39
|
//------------------------------------------------------------------------------
|
@@ -60,7 +60,7 @@ function canBecomeVariableDeclaration(identifier) {
|
|
60
60
|
*/
|
61
61
|
function isOuterVariableInDestructing(name, initScope) {
|
62
62
|
|
63
|
-
if (initScope.through.
|
63
|
+
if (initScope.through.some(ref => ref.resolved && ref.resolved.name === name)) {
|
64
64
|
return true;
|
65
65
|
}
|
66
66
|
|
@@ -106,7 +106,7 @@ module.exports = {
|
|
106
106
|
const methodName = (node.callee.property || {}).name;
|
107
107
|
const isReflectCall = (node.callee.object || {}).name === "Reflect";
|
108
108
|
const hasReflectSubstitute = Object.prototype.hasOwnProperty.call(reflectSubstitutes, methodName);
|
109
|
-
const userConfiguredException = exceptions.
|
109
|
+
const userConfiguredException = exceptions.includes(methodName);
|
110
110
|
|
111
111
|
if (hasReflectSubstitute && !isReflectCall && !userConfiguredException) {
|
112
112
|
report(node, existingNames[methodName], reflectSubstitutes[methodName]);
|
@@ -115,7 +115,7 @@ module.exports = {
|
|
115
115
|
UnaryExpression(node) {
|
116
116
|
const isDeleteOperator = node.operator === "delete";
|
117
117
|
const targetsIdentifier = node.argument.type === "Identifier";
|
118
|
-
const userConfiguredException = exceptions.
|
118
|
+
const userConfiguredException = exceptions.includes("delete");
|
119
119
|
|
120
120
|
if (isDeleteOperator && !targetsIdentifier && !userConfiguredException) {
|
121
121
|
report(node, "the delete keyword", "Reflect.deleteProperty");
|
@@ -47,7 +47,7 @@ function isStaticTemplateLiteral(node) {
|
|
47
47
|
return node.type === "TemplateLiteral" && node.expressions.length === 0;
|
48
48
|
}
|
49
49
|
|
50
|
-
const validPrecedingTokens = [
|
50
|
+
const validPrecedingTokens = new Set([
|
51
51
|
"(",
|
52
52
|
";",
|
53
53
|
"[",
|
@@ -110,7 +110,7 @@ const validPrecedingTokens = [
|
|
110
110
|
"debugger",
|
111
111
|
"case",
|
112
112
|
"throw"
|
113
|
-
];
|
113
|
+
]);
|
114
114
|
|
115
115
|
|
116
116
|
//------------------------------------------------------------------------------
|
@@ -334,7 +334,7 @@ module.exports = {
|
|
334
334
|
|
335
335
|
const tokenBefore = sourceCode.getTokenBefore(node);
|
336
336
|
|
337
|
-
if (tokenBefore && !validPrecedingTokens.
|
337
|
+
if (tokenBefore && !validPrecedingTokens.has(tokenBefore.value)) {
|
338
338
|
noFix = true;
|
339
339
|
}
|
340
340
|
|