eslint 8.34.0 → 8.39.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 +7 -18
- package/conf/rule-type-list.json +2 -2
- package/lib/cli-engine/cli-engine.js +2 -2
- package/lib/cli-engine/file-enumerator.js +8 -6
- package/lib/config/default-config.js +1 -4
- package/lib/config/flat-config-array.js +77 -17
- package/lib/config/flat-config-schema.js +4 -18
- package/lib/eslint/eslint-helpers.js +3 -3
- package/lib/linter/linter.js +4 -77
- package/lib/rule-tester/flat-rule-tester.js +1 -1
- package/lib/rule-tester/rule-tester.js +1 -1
- package/lib/rules/block-scoped-var.js +2 -1
- package/lib/rules/camelcase.js +5 -4
- package/lib/rules/consistent-this.js +4 -2
- package/lib/rules/func-names.js +1 -1
- package/lib/rules/global-require.js +4 -2
- package/lib/rules/handle-callback-err.js +2 -1
- package/lib/rules/id-blacklist.js +3 -2
- package/lib/rules/id-denylist.js +3 -2
- package/lib/rules/id-match.js +3 -2
- package/lib/rules/lines-around-comment.js +11 -0
- package/lib/rules/logical-assignment-operators.js +4 -4
- package/lib/rules/multiline-comment-style.js +42 -3
- package/lib/rules/new-parens.js +5 -14
- package/lib/rules/no-alert.js +3 -1
- package/lib/rules/no-catch-shadow.js +3 -1
- package/lib/rules/no-class-assign.js +3 -1
- package/lib/rules/no-console.js +3 -2
- package/lib/rules/no-const-assign.js +3 -1
- package/lib/rules/no-constant-binary-expression.js +36 -27
- package/lib/rules/no-constant-condition.js +3 -2
- package/lib/rules/no-control-regex.js +1 -1
- package/lib/rules/no-div-regex.js +1 -1
- package/lib/rules/no-dupe-args.js +3 -1
- package/lib/rules/no-else-return.js +13 -12
- package/lib/rules/no-eval.js +5 -5
- package/lib/rules/no-ex-assign.js +3 -1
- package/lib/rules/no-extend-native.js +3 -2
- package/lib/rules/no-extra-boolean-cast.js +1 -1
- package/lib/rules/no-extra-parens.js +1 -1
- package/lib/rules/no-func-assign.js +3 -1
- package/lib/rules/no-global-assign.js +3 -2
- package/lib/rules/no-implicit-globals.js +3 -2
- package/lib/rules/no-implied-eval.js +5 -4
- package/lib/rules/no-import-assign.js +5 -3
- package/lib/rules/no-invalid-regexp.js +1 -1
- package/lib/rules/no-invalid-this.js +2 -2
- package/lib/rules/no-label-var.js +2 -1
- package/lib/rules/no-lone-blocks.js +8 -6
- package/lib/rules/no-lonely-if.js +2 -3
- package/lib/rules/no-loop-func.js +3 -1
- package/lib/rules/no-misleading-character-class.js +12 -41
- package/lib/rules/no-native-reassign.js +3 -2
- package/lib/rules/no-new-func.js +7 -6
- package/lib/rules/no-new-native-nonconstructor.js +8 -6
- package/lib/rules/no-new-object.js +4 -1
- package/lib/rules/no-new-symbol.js +8 -6
- package/lib/rules/no-obj-calls.js +8 -6
- package/lib/rules/no-param-reassign.js +2 -1
- package/lib/rules/no-promise-executor-return.js +3 -2
- package/lib/rules/no-redeclare.js +3 -3
- package/lib/rules/no-regex-spaces.js +4 -2
- package/lib/rules/no-restricted-exports.js +2 -1
- package/lib/rules/no-restricted-globals.js +4 -2
- package/lib/rules/no-setter-return.js +3 -2
- package/lib/rules/no-shadow-restricted-names.js +2 -1
- package/lib/rules/no-shadow.js +3 -2
- package/lib/rules/no-undef-init.js +1 -1
- package/lib/rules/no-undef.js +3 -2
- package/lib/rules/no-undefined.js +4 -2
- package/lib/rules/no-underscore-dangle.js +2 -1
- package/lib/rules/no-unmodified-loop-condition.js +2 -2
- package/lib/rules/no-unused-expressions.js +4 -5
- package/lib/rules/no-unused-vars.js +2 -2
- package/lib/rules/no-use-before-define.js +3 -2
- package/lib/rules/no-useless-backreference.js +9 -7
- package/lib/rules/no-useless-return.js +1 -1
- package/lib/rules/no-var.js +2 -2
- package/lib/rules/object-shorthand.js +3 -2
- package/lib/rules/prefer-arrow-callback.js +2 -2
- package/lib/rules/prefer-const.js +1 -1
- package/lib/rules/prefer-exponentiation-operator.js +5 -5
- package/lib/rules/prefer-named-capture-group.js +8 -8
- package/lib/rules/prefer-object-has-own.js +4 -2
- package/lib/rules/prefer-object-spread.js +12 -13
- package/lib/rules/prefer-promise-reject-errors.js +2 -1
- package/lib/rules/prefer-regex-literals.js +26 -27
- package/lib/rules/prefer-rest-params.js +5 -2
- package/lib/rules/radix.js +11 -11
- package/lib/rules/require-atomic-updates.js +2 -2
- package/lib/rules/require-unicode-regexp.js +67 -7
- package/lib/rules/symbol-description.js +7 -5
- package/lib/rules/utils/regular-expressions.js +42 -0
- package/lib/rules/valid-typeof.js +4 -4
- package/lib/rules/wrap-iife.js +1 -1
- package/lib/rules/wrap-regex.js +2 -3
- package/lib/rules/yoda.js +1 -1
- package/lib/source-code/source-code.js +137 -1
- package/lib/source-code/token-store/index.js +1 -1
- package/lib/source-code/token-store/utils.js +35 -20
- package/messages/no-config-found.js +1 -1
- package/package.json +13 -8
- package/conf/eslint-all.js +0 -31
- package/conf/eslint-recommended.js +0 -76
package/lib/rules/id-denylist.js
CHANGED
@@ -121,6 +121,7 @@ module.exports = {
|
|
121
121
|
|
122
122
|
const denyList = new Set(context.options);
|
123
123
|
const reportedNodes = new Set();
|
124
|
+
const sourceCode = context.getSourceCode();
|
124
125
|
|
125
126
|
let globalScope;
|
126
127
|
|
@@ -210,8 +211,8 @@ module.exports = {
|
|
210
211
|
|
211
212
|
return {
|
212
213
|
|
213
|
-
Program() {
|
214
|
-
globalScope =
|
214
|
+
Program(node) {
|
215
|
+
globalScope = sourceCode.getScope(node);
|
215
216
|
},
|
216
217
|
|
217
218
|
[[
|
package/lib/rules/id-match.js
CHANGED
@@ -67,6 +67,7 @@ module.exports = {
|
|
67
67
|
onlyDeclarations = !!options.onlyDeclarations,
|
68
68
|
ignoreDestructuring = !!options.ignoreDestructuring;
|
69
69
|
|
70
|
+
const sourceCode = context.getSourceCode();
|
70
71
|
let globalScope;
|
71
72
|
|
72
73
|
//--------------------------------------------------------------------------
|
@@ -170,8 +171,8 @@ module.exports = {
|
|
170
171
|
|
171
172
|
return {
|
172
173
|
|
173
|
-
Program() {
|
174
|
-
globalScope =
|
174
|
+
Program(node) {
|
175
|
+
globalScope = sourceCode.getScope(node);
|
175
176
|
},
|
176
177
|
|
177
178
|
Identifier(node) {
|
@@ -113,6 +113,10 @@ module.exports = {
|
|
113
113
|
},
|
114
114
|
applyDefaultIgnorePatterns: {
|
115
115
|
type: "boolean"
|
116
|
+
},
|
117
|
+
afterHashbangComment: {
|
118
|
+
type: "boolean",
|
119
|
+
default: false
|
116
120
|
}
|
117
121
|
},
|
118
122
|
additionalProperties: false
|
@@ -449,6 +453,13 @@ module.exports = {
|
|
449
453
|
before: options.beforeBlockComment
|
450
454
|
});
|
451
455
|
}
|
456
|
+
} else if (token.type === "Shebang") {
|
457
|
+
if (options.afterHashbangComment) {
|
458
|
+
checkForEmptyLine(token, {
|
459
|
+
after: options.afterHashbangComment,
|
460
|
+
before: false
|
461
|
+
});
|
462
|
+
}
|
452
463
|
}
|
453
464
|
});
|
454
465
|
}
|
@@ -112,7 +112,7 @@ function isBooleanCast(expression, scope) {
|
|
112
112
|
/**
|
113
113
|
* Returns true for:
|
114
114
|
* truthiness checks: value, Boolean(value), !!value
|
115
|
-
*
|
115
|
+
* falsiness checks: !value, !Boolean(value)
|
116
116
|
* nullish checks: value == null, value === undefined || value === null
|
117
117
|
* @param {ASTNode} expression Test condition
|
118
118
|
* @param {import('eslint-scope').Scope} scope Scope of the expression
|
@@ -159,7 +159,7 @@ module.exports = {
|
|
159
159
|
type: "suggestion",
|
160
160
|
|
161
161
|
docs: {
|
162
|
-
description: "Require or disallow logical assignment
|
162
|
+
description: "Require or disallow logical assignment operator shorthand",
|
163
163
|
recommended: false,
|
164
164
|
url: "https://eslint.org/docs/rules/logical-assignment-operators"
|
165
165
|
},
|
@@ -206,7 +206,7 @@ module.exports = {
|
|
206
206
|
const mode = context.options[0] === "never" ? "never" : "always";
|
207
207
|
const checkIf = mode === "always" && context.options.length > 1 && context.options[1].enforceForIfStatements;
|
208
208
|
const sourceCode = context.getSourceCode();
|
209
|
-
const isStrict =
|
209
|
+
const isStrict = sourceCode.getScope(sourceCode.ast).isStrict;
|
210
210
|
|
211
211
|
/**
|
212
212
|
* Returns false if the access could be a getter
|
@@ -409,7 +409,7 @@ module.exports = {
|
|
409
409
|
}
|
410
410
|
|
411
411
|
const body = hasBody ? ifNode.consequent.body[0] : ifNode.consequent;
|
412
|
-
const scope =
|
412
|
+
const scope = sourceCode.getScope(ifNode);
|
413
413
|
const existence = getExistence(ifNode.test, scope);
|
414
414
|
|
415
415
|
if (
|
@@ -22,7 +22,37 @@ module.exports = {
|
|
22
22
|
},
|
23
23
|
|
24
24
|
fixable: "whitespace",
|
25
|
-
schema:
|
25
|
+
schema: {
|
26
|
+
anyOf: [
|
27
|
+
{
|
28
|
+
type: "array",
|
29
|
+
items: [
|
30
|
+
{
|
31
|
+
enum: ["starred-block", "bare-block"]
|
32
|
+
}
|
33
|
+
],
|
34
|
+
additionalItems: false
|
35
|
+
},
|
36
|
+
{
|
37
|
+
type: "array",
|
38
|
+
items: [
|
39
|
+
{
|
40
|
+
enum: ["separate-lines"]
|
41
|
+
},
|
42
|
+
{
|
43
|
+
type: "object",
|
44
|
+
properties: {
|
45
|
+
checkJSDoc: {
|
46
|
+
type: "boolean"
|
47
|
+
}
|
48
|
+
},
|
49
|
+
additionalProperties: false
|
50
|
+
}
|
51
|
+
],
|
52
|
+
additionalItems: false
|
53
|
+
}
|
54
|
+
]
|
55
|
+
},
|
26
56
|
messages: {
|
27
57
|
expectedBlock: "Expected a block comment instead of consecutive line comments.",
|
28
58
|
expectedBareBlock: "Expected a block comment without padding stars.",
|
@@ -37,6 +67,8 @@ module.exports = {
|
|
37
67
|
create(context) {
|
38
68
|
const sourceCode = context.getSourceCode();
|
39
69
|
const option = context.options[0] || "starred-block";
|
70
|
+
const params = context.options[1] || {};
|
71
|
+
const checkJSDoc = !!params.checkJSDoc;
|
40
72
|
|
41
73
|
//----------------------------------------------------------------------
|
42
74
|
// Helpers
|
@@ -333,11 +365,18 @@ module.exports = {
|
|
333
365
|
"separate-lines"(commentGroup) {
|
334
366
|
const [firstComment] = commentGroup;
|
335
367
|
|
336
|
-
|
368
|
+
const isJSDoc = isJSDocComment(commentGroup);
|
369
|
+
|
370
|
+
if (firstComment.type !== "Block" || (!checkJSDoc && isJSDoc)) {
|
337
371
|
return;
|
338
372
|
}
|
339
373
|
|
340
|
-
|
374
|
+
let commentLines = getCommentLines(commentGroup);
|
375
|
+
|
376
|
+
if (isJSDoc) {
|
377
|
+
commentLines = commentLines.slice(1, commentLines.length - 1);
|
378
|
+
}
|
379
|
+
|
341
380
|
const tokenAfter = sourceCode.getTokenAfter(firstComment, { includeComments: true });
|
342
381
|
|
343
382
|
if (tokenAfter && firstComment.loc.end.line === tokenAfter.loc.start.line) {
|
package/lib/rules/new-parens.js
CHANGED
@@ -31,20 +31,11 @@ module.exports = {
|
|
31
31
|
},
|
32
32
|
|
33
33
|
fixable: "code",
|
34
|
-
schema:
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
{
|
40
|
-
enum: ["always", "never"]
|
41
|
-
}
|
42
|
-
],
|
43
|
-
minItems: 0,
|
44
|
-
maxItems: 1
|
45
|
-
}
|
46
|
-
]
|
47
|
-
},
|
34
|
+
schema: [
|
35
|
+
{
|
36
|
+
enum: ["always", "never"]
|
37
|
+
}
|
38
|
+
],
|
48
39
|
messages: {
|
49
40
|
missing: "Missing '()' invoking a constructor.",
|
50
41
|
unnecessary: "Unnecessary '()' invoking a constructor with no arguments."
|
package/lib/rules/no-alert.js
CHANGED
@@ -101,10 +101,12 @@ module.exports = {
|
|
101
101
|
},
|
102
102
|
|
103
103
|
create(context) {
|
104
|
+
const sourceCode = context.getSourceCode();
|
105
|
+
|
104
106
|
return {
|
105
107
|
CallExpression(node) {
|
106
108
|
const callee = skipChainExpression(node.callee),
|
107
|
-
currentScope =
|
109
|
+
currentScope = sourceCode.getScope(node);
|
108
110
|
|
109
111
|
// without window.
|
110
112
|
if (callee.type === "Identifier") {
|
@@ -39,6 +39,8 @@ module.exports = {
|
|
39
39
|
|
40
40
|
create(context) {
|
41
41
|
|
42
|
+
const sourceCode = context.getSourceCode();
|
43
|
+
|
42
44
|
//--------------------------------------------------------------------------
|
43
45
|
// Helpers
|
44
46
|
//--------------------------------------------------------------------------
|
@@ -60,7 +62,7 @@ module.exports = {
|
|
60
62
|
return {
|
61
63
|
|
62
64
|
"CatchClause[param!=null]"(node) {
|
63
|
-
let scope =
|
65
|
+
let scope = sourceCode.getScope(node);
|
64
66
|
|
65
67
|
/*
|
66
68
|
* When ecmaVersion >= 6, CatchClause creates its own scope
|
@@ -31,6 +31,8 @@ module.exports = {
|
|
31
31
|
|
32
32
|
create(context) {
|
33
33
|
|
34
|
+
const sourceCode = context.getSourceCode();
|
35
|
+
|
34
36
|
/**
|
35
37
|
* Finds and reports references that are non initializer and writable.
|
36
38
|
* @param {Variable} variable A variable to check.
|
@@ -49,7 +51,7 @@ module.exports = {
|
|
49
51
|
* @returns {void}
|
50
52
|
*/
|
51
53
|
function checkForClass(node) {
|
52
|
-
|
54
|
+
sourceCode.getDeclaredVariables(node).forEach(checkVariable);
|
53
55
|
}
|
54
56
|
|
55
57
|
return {
|
package/lib/rules/no-console.js
CHANGED
@@ -51,6 +51,7 @@ module.exports = {
|
|
51
51
|
create(context) {
|
52
52
|
const options = context.options[0] || {};
|
53
53
|
const allowed = options.allow || [];
|
54
|
+
const sourceCode = context.getSourceCode();
|
54
55
|
|
55
56
|
/**
|
56
57
|
* Checks whether the given reference is 'console' or not.
|
@@ -109,8 +110,8 @@ module.exports = {
|
|
109
110
|
}
|
110
111
|
|
111
112
|
return {
|
112
|
-
"Program:exit"() {
|
113
|
-
const scope =
|
113
|
+
"Program:exit"(node) {
|
114
|
+
const scope = sourceCode.getScope(node);
|
114
115
|
const consoleVar = astUtils.getVariableByName(scope, "console");
|
115
116
|
const shadowed = consoleVar && consoleVar.defs.length > 0;
|
116
117
|
|
@@ -31,6 +31,8 @@ module.exports = {
|
|
31
31
|
|
32
32
|
create(context) {
|
33
33
|
|
34
|
+
const sourceCode = context.getSourceCode();
|
35
|
+
|
34
36
|
/**
|
35
37
|
* Finds and reports references that are non initializer and writable.
|
36
38
|
* @param {Variable} variable A variable to check.
|
@@ -45,7 +47,7 @@ module.exports = {
|
|
45
47
|
return {
|
46
48
|
VariableDeclaration(node) {
|
47
49
|
if (node.kind === "const") {
|
48
|
-
|
50
|
+
sourceCode.getDeclaredVariables(node).forEach(checkVariable);
|
49
51
|
}
|
50
52
|
}
|
51
53
|
};
|
@@ -14,6 +14,23 @@ const NUMERIC_OR_STRING_BINARY_OPERATORS = new Set(["+", "-", "*", "/", "%", "|"
|
|
14
14
|
// Helpers
|
15
15
|
//------------------------------------------------------------------------------
|
16
16
|
|
17
|
+
/**
|
18
|
+
* Checks whether or not a node is `null` or `undefined`. Similar to the one
|
19
|
+
* found in ast-utils.js, but this one correctly handles the edge case that
|
20
|
+
* `undefined` has been redefined.
|
21
|
+
* @param {Scope} scope Scope in which the expression was found.
|
22
|
+
* @param {ASTNode} node A node to check.
|
23
|
+
* @returns {boolean} Whether or not the node is a `null` or `undefined`.
|
24
|
+
* @public
|
25
|
+
*/
|
26
|
+
function isNullOrUndefined(scope, node) {
|
27
|
+
return (
|
28
|
+
isNullLiteral(node) ||
|
29
|
+
(node.type === "Identifier" && node.name === "undefined" && isReferenceToGlobalVariable(scope, node)) ||
|
30
|
+
(node.type === "UnaryExpression" && node.operator === "void")
|
31
|
+
);
|
32
|
+
}
|
33
|
+
|
17
34
|
/**
|
18
35
|
* Test if an AST node has a statically knowable constant nullishness. Meaning,
|
19
36
|
* it will always resolve to a constant value of either: `null`, `undefined`
|
@@ -21,9 +38,14 @@ const NUMERIC_OR_STRING_BINARY_OPERATORS = new Set(["+", "-", "*", "/", "%", "|"
|
|
21
38
|
* three states at runtime would return `false`.
|
22
39
|
* @param {Scope} scope The scope in which the node was found.
|
23
40
|
* @param {ASTNode} node The AST node being tested.
|
41
|
+
* @param {boolean} nonNullish if `true` then nullish values are not considered constant.
|
24
42
|
* @returns {boolean} Does `node` have constant nullishness?
|
25
43
|
*/
|
26
|
-
function hasConstantNullishness(scope, node) {
|
44
|
+
function hasConstantNullishness(scope, node, nonNullish) {
|
45
|
+
if (nonNullish && isNullOrUndefined(scope, node)) {
|
46
|
+
return false;
|
47
|
+
}
|
48
|
+
|
27
49
|
switch (node.type) {
|
28
50
|
case "ObjectExpression": // Objects are never nullish
|
29
51
|
case "ArrayExpression": // Arrays are never nullish
|
@@ -45,9 +67,12 @@ function hasConstantNullishness(scope, node) {
|
|
45
67
|
return (functionName === "Boolean" || functionName === "String" || functionName === "Number") &&
|
46
68
|
isReferenceToGlobalVariable(scope, node.callee);
|
47
69
|
}
|
70
|
+
case "LogicalExpression": {
|
71
|
+
return node.operator === "??" && hasConstantNullishness(scope, node.right, true);
|
72
|
+
}
|
48
73
|
case "AssignmentExpression":
|
49
74
|
if (node.operator === "=") {
|
50
|
-
return hasConstantNullishness(scope, node.right);
|
75
|
+
return hasConstantNullishness(scope, node.right, nonNullish);
|
51
76
|
}
|
52
77
|
|
53
78
|
/*
|
@@ -80,7 +105,7 @@ function hasConstantNullishness(scope, node) {
|
|
80
105
|
case "SequenceExpression": {
|
81
106
|
const last = node.expressions[node.expressions.length - 1];
|
82
107
|
|
83
|
-
return hasConstantNullishness(scope, last);
|
108
|
+
return hasConstantNullishness(scope, last, nonNullish);
|
84
109
|
}
|
85
110
|
case "Identifier":
|
86
111
|
return node.name === "undefined" && isReferenceToGlobalVariable(scope, node);
|
@@ -348,7 +373,7 @@ function isAlwaysNew(scope, node) {
|
|
348
373
|
* user-defined constructors could return a sentinel
|
349
374
|
* object.
|
350
375
|
*
|
351
|
-
* Catching these is especially useful for primitive
|
376
|
+
* Catching these is especially useful for primitive constructors
|
352
377
|
* which return boxed values, a surprising gotcha' in JavaScript.
|
353
378
|
*/
|
354
379
|
return Object.hasOwnProperty.call(globals.builtin, node.callee.name) &&
|
@@ -378,24 +403,6 @@ function isAlwaysNew(scope, node) {
|
|
378
403
|
}
|
379
404
|
}
|
380
405
|
|
381
|
-
/**
|
382
|
-
* Checks whether or not a node is `null` or `undefined`. Similar to the one
|
383
|
-
* found in ast-utils.js, but this one correctly handles the edge case that
|
384
|
-
* `undefined` has been redefined.
|
385
|
-
* @param {Scope} scope Scope in which the expression was found.
|
386
|
-
* @param {ASTNode} node A node to check.
|
387
|
-
* @returns {boolean} Whether or not the node is a `null` or `undefined`.
|
388
|
-
* @public
|
389
|
-
*/
|
390
|
-
function isNullOrUndefined(scope, node) {
|
391
|
-
return (
|
392
|
-
isNullLiteral(node) ||
|
393
|
-
(node.type === "Identifier" && node.name === "undefined" && isReferenceToGlobalVariable(scope, node)) ||
|
394
|
-
(node.type === "UnaryExpression" && node.operator === "void")
|
395
|
-
);
|
396
|
-
}
|
397
|
-
|
398
|
-
|
399
406
|
/**
|
400
407
|
* Checks if one operand will cause the result to be constant.
|
401
408
|
* @param {Scope} scope Scope in which the expression was found.
|
@@ -407,14 +414,14 @@ function isNullOrUndefined(scope, node) {
|
|
407
414
|
function findBinaryExpressionConstantOperand(scope, a, b, operator) {
|
408
415
|
if (operator === "==" || operator === "!=") {
|
409
416
|
if (
|
410
|
-
(isNullOrUndefined(scope, a) && hasConstantNullishness(scope, b)) ||
|
417
|
+
(isNullOrUndefined(scope, a) && hasConstantNullishness(scope, b, false)) ||
|
411
418
|
(isStaticBoolean(scope, a) && hasConstantLooseBooleanComparison(scope, b))
|
412
419
|
) {
|
413
420
|
return b;
|
414
421
|
}
|
415
422
|
} else if (operator === "===" || operator === "!==") {
|
416
423
|
if (
|
417
|
-
(isNullOrUndefined(scope, a) && hasConstantNullishness(scope, b)) ||
|
424
|
+
(isNullOrUndefined(scope, a) && hasConstantNullishness(scope, b, false)) ||
|
418
425
|
(isStaticBoolean(scope, a) && hasConstantStrictBooleanComparison(scope, b))
|
419
426
|
) {
|
420
427
|
return b;
|
@@ -446,19 +453,21 @@ module.exports = {
|
|
446
453
|
},
|
447
454
|
|
448
455
|
create(context) {
|
456
|
+
const sourceCode = context.getSourceCode();
|
457
|
+
|
449
458
|
return {
|
450
459
|
LogicalExpression(node) {
|
451
460
|
const { operator, left } = node;
|
452
|
-
const scope =
|
461
|
+
const scope = sourceCode.getScope(node);
|
453
462
|
|
454
463
|
if ((operator === "&&" || operator === "||") && isConstant(scope, left, true)) {
|
455
464
|
context.report({ node: left, messageId: "constantShortCircuit", data: { property: "truthiness", operator } });
|
456
|
-
} else if (operator === "??" && hasConstantNullishness(scope, left)) {
|
465
|
+
} else if (operator === "??" && hasConstantNullishness(scope, left, false)) {
|
457
466
|
context.report({ node: left, messageId: "constantShortCircuit", data: { property: "nullishness", operator } });
|
458
467
|
}
|
459
468
|
},
|
460
469
|
BinaryExpression(node) {
|
461
|
-
const scope =
|
470
|
+
const scope = sourceCode.getScope(node);
|
462
471
|
const { right, left, operator } = node;
|
463
472
|
const rightConstantOperand = findBinaryExpressionConstantOperand(scope, left, right, operator);
|
464
473
|
const leftConstantOperand = findBinaryExpressionConstantOperand(scope, right, left, operator);
|
@@ -48,6 +48,7 @@ module.exports = {
|
|
48
48
|
const options = context.options[0] || {},
|
49
49
|
checkLoops = options.checkLoops !== false,
|
50
50
|
loopSetStack = [];
|
51
|
+
const sourceCode = context.getSourceCode();
|
51
52
|
|
52
53
|
let loopsInCurrentScope = new Set();
|
53
54
|
|
@@ -62,7 +63,7 @@ module.exports = {
|
|
62
63
|
* @private
|
63
64
|
*/
|
64
65
|
function trackConstantConditionLoop(node) {
|
65
|
-
if (node.test && isConstant(
|
66
|
+
if (node.test && isConstant(sourceCode.getScope(node), node.test, true)) {
|
66
67
|
loopsInCurrentScope.add(node);
|
67
68
|
}
|
68
69
|
}
|
@@ -87,7 +88,7 @@ module.exports = {
|
|
87
88
|
* @private
|
88
89
|
*/
|
89
90
|
function reportIfConstant(node) {
|
90
|
-
if (node.test && isConstant(
|
91
|
+
if (node.test && isConstant(sourceCode.getScope(node), node.test, true)) {
|
91
92
|
context.report({ node: node.test, messageId: "unexpected" });
|
92
93
|
}
|
93
94
|
}
|
@@ -15,7 +15,7 @@ module.exports = {
|
|
15
15
|
type: "suggestion",
|
16
16
|
|
17
17
|
docs: {
|
18
|
-
description: "Disallow
|
18
|
+
description: "Disallow equal signs explicitly at the beginning of regular expressions",
|
19
19
|
recommended: false,
|
20
20
|
url: "https://eslint.org/docs/rules/no-div-regex"
|
21
21
|
},
|
@@ -29,6 +29,8 @@ module.exports = {
|
|
29
29
|
|
30
30
|
create(context) {
|
31
31
|
|
32
|
+
const sourceCode = context.getSourceCode();
|
33
|
+
|
32
34
|
//--------------------------------------------------------------------------
|
33
35
|
// Helpers
|
34
36
|
//--------------------------------------------------------------------------
|
@@ -49,7 +51,7 @@ module.exports = {
|
|
49
51
|
* @private
|
50
52
|
*/
|
51
53
|
function checkParams(node) {
|
52
|
-
const variables =
|
54
|
+
const variables = sourceCode.getDeclaredVariables(node);
|
53
55
|
|
54
56
|
for (let i = 0; i < variables.length; ++i) {
|
55
57
|
const variable = variables[i];
|
@@ -47,6 +47,8 @@ module.exports = {
|
|
47
47
|
|
48
48
|
create(context) {
|
49
49
|
|
50
|
+
const sourceCode = context.getSourceCode();
|
51
|
+
|
50
52
|
//--------------------------------------------------------------------------
|
51
53
|
// Helpers
|
52
54
|
//--------------------------------------------------------------------------
|
@@ -169,25 +171,24 @@ module.exports = {
|
|
169
171
|
|
170
172
|
/**
|
171
173
|
* Display the context report if rule is violated
|
172
|
-
* @param {Node}
|
174
|
+
* @param {Node} elseNode The 'else' node
|
173
175
|
* @returns {void}
|
174
176
|
*/
|
175
|
-
function displayReport(
|
176
|
-
const currentScope =
|
177
|
+
function displayReport(elseNode) {
|
178
|
+
const currentScope = sourceCode.getScope(elseNode.parent);
|
177
179
|
|
178
180
|
context.report({
|
179
|
-
node,
|
181
|
+
node: elseNode,
|
180
182
|
messageId: "unexpected",
|
181
183
|
fix(fixer) {
|
182
184
|
|
183
|
-
if (!isSafeFromNameCollisions(
|
185
|
+
if (!isSafeFromNameCollisions(elseNode, currentScope)) {
|
184
186
|
return null;
|
185
187
|
}
|
186
188
|
|
187
|
-
const
|
188
|
-
const startToken = sourceCode.getFirstToken(node);
|
189
|
+
const startToken = sourceCode.getFirstToken(elseNode);
|
189
190
|
const elseToken = sourceCode.getTokenBefore(startToken);
|
190
|
-
const source = sourceCode.getText(
|
191
|
+
const source = sourceCode.getText(elseNode);
|
191
192
|
const lastIfToken = sourceCode.getTokenBefore(elseToken);
|
192
193
|
let fixedSource, firstTokenOfElseBlock;
|
193
194
|
|
@@ -203,14 +204,14 @@ module.exports = {
|
|
203
204
|
* safe to remove the else keyword, because ASI will not add a semicolon
|
204
205
|
* after the if block
|
205
206
|
*/
|
206
|
-
const ifBlockMaybeUnsafe =
|
207
|
+
const ifBlockMaybeUnsafe = elseNode.parent.consequent.type !== "BlockStatement" && lastIfToken.value !== ";";
|
207
208
|
const elseBlockUnsafe = /^[([/+`-]/u.test(firstTokenOfElseBlock.value);
|
208
209
|
|
209
210
|
if (ifBlockMaybeUnsafe && elseBlockUnsafe) {
|
210
211
|
return null;
|
211
212
|
}
|
212
213
|
|
213
|
-
const endToken = sourceCode.getLastToken(
|
214
|
+
const endToken = sourceCode.getLastToken(elseNode);
|
214
215
|
const lastTokenOfElseBlock = sourceCode.getTokenBefore(endToken);
|
215
216
|
|
216
217
|
if (lastTokenOfElseBlock.value !== ";") {
|
@@ -244,8 +245,8 @@ module.exports = {
|
|
244
245
|
* Also, to avoid name collisions between two else blocks.
|
245
246
|
*/
|
246
247
|
return new FixTracker(fixer, sourceCode)
|
247
|
-
.retainEnclosingFunction(
|
248
|
-
.replaceTextRange([elseToken.range[0],
|
248
|
+
.retainEnclosingFunction(elseNode)
|
249
|
+
.replaceTextRange([elseToken.range[0], elseNode.range[1]], fixedSource);
|
249
250
|
}
|
250
251
|
});
|
251
252
|
}
|
package/lib/rules/no-eval.js
CHANGED
@@ -72,7 +72,7 @@ module.exports = {
|
|
72
72
|
let funcInfo = null;
|
73
73
|
|
74
74
|
/**
|
75
|
-
*
|
75
|
+
* Pushes a `this` scope (non-arrow function, class static block, or class field initializer) information to the stack.
|
76
76
|
* Top-level scopes are handled separately.
|
77
77
|
*
|
78
78
|
* This is used in order to check whether or not `this` binding is a
|
@@ -84,7 +84,7 @@ module.exports = {
|
|
84
84
|
* @returns {void}
|
85
85
|
*/
|
86
86
|
function enterThisScope(node) {
|
87
|
-
const strict =
|
87
|
+
const strict = sourceCode.getScope(node).isStrict;
|
88
88
|
|
89
89
|
funcInfo = {
|
90
90
|
upper: funcInfo,
|
@@ -221,7 +221,7 @@ module.exports = {
|
|
221
221
|
},
|
222
222
|
|
223
223
|
Program(node) {
|
224
|
-
const scope =
|
224
|
+
const scope = sourceCode.getScope(node),
|
225
225
|
features = context.parserOptions.ecmaFeatures || {},
|
226
226
|
strict =
|
227
227
|
scope.isStrict ||
|
@@ -239,8 +239,8 @@ module.exports = {
|
|
239
239
|
};
|
240
240
|
},
|
241
241
|
|
242
|
-
"Program:exit"() {
|
243
|
-
const globalScope =
|
242
|
+
"Program:exit"(node) {
|
243
|
+
const globalScope = sourceCode.getScope(node);
|
244
244
|
|
245
245
|
exitThisScope();
|
246
246
|
reportAccessingEval(globalScope);
|
@@ -31,6 +31,8 @@ module.exports = {
|
|
31
31
|
|
32
32
|
create(context) {
|
33
33
|
|
34
|
+
const sourceCode = context.getSourceCode();
|
35
|
+
|
34
36
|
/**
|
35
37
|
* Finds and reports references that are non initializer and writable.
|
36
38
|
* @param {Variable} variable A variable to check.
|
@@ -44,7 +46,7 @@ module.exports = {
|
|
44
46
|
|
45
47
|
return {
|
46
48
|
CatchClause(node) {
|
47
|
-
|
49
|
+
sourceCode.getDeclaredVariables(node).forEach(checkVariable);
|
48
50
|
}
|
49
51
|
};
|
50
52
|
|
@@ -51,6 +51,7 @@ module.exports = {
|
|
51
51
|
create(context) {
|
52
52
|
|
53
53
|
const config = context.options[0] || {};
|
54
|
+
const sourceCode = context.getSourceCode();
|
54
55
|
const exceptions = new Set(config.exceptions || []);
|
55
56
|
const modifiedBuiltins = new Set(
|
56
57
|
Object.keys(globals.builtin)
|
@@ -159,8 +160,8 @@ module.exports = {
|
|
159
160
|
|
160
161
|
return {
|
161
162
|
|
162
|
-
"Program:exit"() {
|
163
|
-
const globalScope =
|
163
|
+
"Program:exit"(node) {
|
164
|
+
const globalScope = sourceCode.getScope(node);
|
164
165
|
|
165
166
|
modifiedBuiltins.forEach(builtin => {
|
166
167
|
const builtinVar = globalScope.set.get(builtin);
|
@@ -10,7 +10,7 @@
|
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
12
|
const astUtils = require("./utils/ast-utils");
|
13
|
-
const eslintUtils = require("eslint-utils");
|
13
|
+
const eslintUtils = require("@eslint-community/eslint-utils");
|
14
14
|
|
15
15
|
const precedence = astUtils.getPrecedence;
|
16
16
|
|
@@ -8,7 +8,7 @@
|
|
8
8
|
// Rule Definition
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
|
-
const { isParenthesized: isParenthesizedRaw } = require("eslint-utils");
|
11
|
+
const { isParenthesized: isParenthesizedRaw } = require("@eslint-community/eslint-utils");
|
12
12
|
const astUtils = require("./utils/ast-utils.js");
|
13
13
|
|
14
14
|
/** @type {import('../shared/types').Rule} */
|