eslint 8.50.0 → 8.52.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 -2
- package/bin/eslint.js +15 -4
- package/conf/rule-type-list.json +25 -33
- package/lib/cli.js +14 -3
- package/lib/config/flat-config-schema.js +56 -39
- package/lib/eslint/eslint-helpers.js +8 -3
- package/lib/eslint/flat-eslint.js +15 -6
- package/lib/linter/apply-disable-directives.js +127 -13
- package/lib/linter/code-path-analysis/code-path-state.js +1108 -243
- package/lib/linter/code-path-analysis/code-path.js +127 -33
- package/lib/linter/code-path-analysis/fork-context.js +173 -72
- package/lib/linter/config-comment-parser.js +1 -1
- package/lib/options.js +15 -2
- package/lib/rules/logical-assignment-operators.js +31 -3
- package/lib/rules/no-object-constructor.js +103 -5
- package/package.json +4 -3
@@ -139,7 +139,7 @@ module.exports = class ConfigCommentParser {
|
|
139
139
|
const items = {};
|
140
140
|
|
141
141
|
string.split(",").forEach(name => {
|
142
|
-
const trimmedName = name.trim();
|
142
|
+
const trimmedName = name.trim().replace(/^(?<quote>['"]?)(?<ruleId>.*)\k<quote>$/us, "$<ruleId>");
|
143
143
|
|
144
144
|
if (trimmedName) {
|
145
145
|
items[trimmedName] = true;
|
package/lib/options.js
CHANGED
@@ -47,7 +47,7 @@ const optionator = require("optionator");
|
|
47
47
|
* @property {Object} [parserOptions] Specify parser options
|
48
48
|
* @property {string[]} [plugin] Specify plugins
|
49
49
|
* @property {string} [printConfig] Print the configuration for the given file
|
50
|
-
* @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable directives
|
50
|
+
* @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable and eslint-enable directives
|
51
51
|
* @property {string} [resolvePluginsRelativeTo] A folder where plugins should be resolved from, CWD by default
|
52
52
|
* @property {Object} [rule] Specify rules
|
53
53
|
* @property {string[]} [rulesdir] Load additional rules from this directory. Deprecated: Use rules from plugins
|
@@ -55,6 +55,7 @@ const optionator = require("optionator");
|
|
55
55
|
* @property {string} [stdinFilename] Specify filename to process STDIN as
|
56
56
|
* @property {boolean} quiet Report errors only
|
57
57
|
* @property {boolean} [version] Output the version number
|
58
|
+
* @property {boolean} warnIgnored Show warnings when the file list includes ignored files
|
58
59
|
* @property {string[]} _ Positional filenames or patterns
|
59
60
|
*/
|
60
61
|
|
@@ -139,6 +140,17 @@ module.exports = function(usingFlatConfig) {
|
|
139
140
|
};
|
140
141
|
}
|
141
142
|
|
143
|
+
let warnIgnoredFlag;
|
144
|
+
|
145
|
+
if (usingFlatConfig) {
|
146
|
+
warnIgnoredFlag = {
|
147
|
+
option: "warn-ignored",
|
148
|
+
type: "Boolean",
|
149
|
+
default: "true",
|
150
|
+
description: "Suppress warnings when the file list includes ignored files"
|
151
|
+
};
|
152
|
+
}
|
153
|
+
|
142
154
|
return optionator({
|
143
155
|
prepend: "eslint [options] file.js [file.js] [dir]",
|
144
156
|
defaults: {
|
@@ -292,7 +304,7 @@ module.exports = function(usingFlatConfig) {
|
|
292
304
|
option: "report-unused-disable-directives",
|
293
305
|
type: "Boolean",
|
294
306
|
default: void 0,
|
295
|
-
description: "Adds reported errors for unused eslint-disable directives"
|
307
|
+
description: "Adds reported errors for unused eslint-disable and eslint-enable directives"
|
296
308
|
},
|
297
309
|
{
|
298
310
|
heading: "Caching"
|
@@ -349,6 +361,7 @@ module.exports = function(usingFlatConfig) {
|
|
349
361
|
default: "false",
|
350
362
|
description: "Exit with exit code 2 in case of fatal error"
|
351
363
|
},
|
364
|
+
warnIgnoredFlag,
|
352
365
|
{
|
353
366
|
option: "debug",
|
354
367
|
type: "Boolean",
|
@@ -150,6 +150,31 @@ function isInsideWithBlock(node) {
|
|
150
150
|
return node.parent.type === "WithStatement" && node.parent.body === node ? true : isInsideWithBlock(node.parent);
|
151
151
|
}
|
152
152
|
|
153
|
+
/**
|
154
|
+
* Gets the leftmost operand of a consecutive logical expression.
|
155
|
+
* @param {SourceCode} sourceCode The ESLint source code object
|
156
|
+
* @param {LogicalExpression} node LogicalExpression
|
157
|
+
* @returns {Expression} Leftmost operand
|
158
|
+
*/
|
159
|
+
function getLeftmostOperand(sourceCode, node) {
|
160
|
+
let left = node.left;
|
161
|
+
|
162
|
+
while (left.type === "LogicalExpression" && left.operator === node.operator) {
|
163
|
+
|
164
|
+
if (astUtils.isParenthesised(sourceCode, left)) {
|
165
|
+
|
166
|
+
/*
|
167
|
+
* It should have associativity,
|
168
|
+
* but ignore it if use parentheses to make the evaluation order clear.
|
169
|
+
*/
|
170
|
+
return left;
|
171
|
+
}
|
172
|
+
left = left.left;
|
173
|
+
}
|
174
|
+
return left;
|
175
|
+
|
176
|
+
}
|
177
|
+
|
153
178
|
//------------------------------------------------------------------------------
|
154
179
|
// Rule Definition
|
155
180
|
//------------------------------------------------------------------------------
|
@@ -318,7 +343,10 @@ module.exports = {
|
|
318
343
|
|
319
344
|
// foo = foo || bar
|
320
345
|
"AssignmentExpression[operator='='][right.type='LogicalExpression']"(assignment) {
|
321
|
-
|
346
|
+
const leftOperand = getLeftmostOperand(sourceCode, assignment.right);
|
347
|
+
|
348
|
+
if (!astUtils.isSameReference(assignment.left, leftOperand)
|
349
|
+
) {
|
322
350
|
return;
|
323
351
|
}
|
324
352
|
|
@@ -342,10 +370,10 @@ module.exports = {
|
|
342
370
|
yield ruleFixer.insertTextBefore(assignmentOperatorToken, assignment.right.operator);
|
343
371
|
|
344
372
|
// -> foo ||= bar
|
345
|
-
const logicalOperatorToken = getOperatorToken(
|
373
|
+
const logicalOperatorToken = getOperatorToken(leftOperand.parent);
|
346
374
|
const firstRightOperandToken = sourceCode.getTokenAfter(logicalOperatorToken);
|
347
375
|
|
348
|
-
yield ruleFixer.removeRange([
|
376
|
+
yield ruleFixer.removeRange([leftOperand.parent.range[0], firstRightOperandToken.range[0]]);
|
349
377
|
}
|
350
378
|
};
|
351
379
|
|
@@ -9,12 +9,51 @@
|
|
9
9
|
// Requirements
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
|
-
const { getVariableByName, isArrowToken } = require("./utils/ast-utils");
|
12
|
+
const { getVariableByName, isArrowToken, isClosingBraceToken, isClosingParenToken } = require("./utils/ast-utils");
|
13
13
|
|
14
14
|
//------------------------------------------------------------------------------
|
15
15
|
// Helpers
|
16
16
|
//------------------------------------------------------------------------------
|
17
17
|
|
18
|
+
const BREAK_OR_CONTINUE = new Set(["BreakStatement", "ContinueStatement"]);
|
19
|
+
|
20
|
+
// Declaration types that must contain a string Literal node at the end.
|
21
|
+
const DECLARATIONS = new Set(["ExportAllDeclaration", "ExportNamedDeclaration", "ImportDeclaration"]);
|
22
|
+
|
23
|
+
const IDENTIFIER_OR_KEYWORD = new Set(["Identifier", "Keyword"]);
|
24
|
+
|
25
|
+
// Keywords that can immediately precede an ExpressionStatement node, mapped to the their node types.
|
26
|
+
const NODE_TYPES_BY_KEYWORD = {
|
27
|
+
__proto__: null,
|
28
|
+
break: "BreakStatement",
|
29
|
+
continue: "ContinueStatement",
|
30
|
+
debugger: "DebuggerStatement",
|
31
|
+
do: "DoWhileStatement",
|
32
|
+
else: "IfStatement",
|
33
|
+
return: "ReturnStatement",
|
34
|
+
yield: "YieldExpression"
|
35
|
+
};
|
36
|
+
|
37
|
+
/*
|
38
|
+
* Before an opening parenthesis, `>` (for JSX), and postfix `++` and `--` always trigger ASI;
|
39
|
+
* the tokens `:`, `;`, `{` and `=>` don't expect a semicolon, as that would count as an empty statement.
|
40
|
+
*/
|
41
|
+
const PUNCTUATORS = new Set([":", ";", ">", "{", "=>", "++", "--"]);
|
42
|
+
|
43
|
+
/*
|
44
|
+
* Statements that can contain an `ExpressionStatement` after a closing parenthesis.
|
45
|
+
* DoWhileStatement is an exception in that it always triggers ASI after the closing parenthesis.
|
46
|
+
*/
|
47
|
+
const STATEMENTS = new Set([
|
48
|
+
"DoWhileStatement",
|
49
|
+
"ForInStatement",
|
50
|
+
"ForOfStatement",
|
51
|
+
"ForStatement",
|
52
|
+
"IfStatement",
|
53
|
+
"WhileStatement",
|
54
|
+
"WithStatement"
|
55
|
+
]);
|
56
|
+
|
18
57
|
/**
|
19
58
|
* Tests if a node appears at the beginning of an ancestor ExpressionStatement node.
|
20
59
|
* @param {ASTNode} node The node to check.
|
@@ -53,7 +92,8 @@ module.exports = {
|
|
53
92
|
|
54
93
|
messages: {
|
55
94
|
preferLiteral: "The object literal notation {} is preferable.",
|
56
|
-
useLiteral: "Replace with '{{replacement}}'."
|
95
|
+
useLiteral: "Replace with '{{replacement}}'.",
|
96
|
+
useLiteralAfterSemicolon: "Replace with '{{replacement}}', add preceding semicolon."
|
57
97
|
}
|
58
98
|
},
|
59
99
|
|
@@ -80,6 +120,50 @@ module.exports = {
|
|
80
120
|
return false;
|
81
121
|
}
|
82
122
|
|
123
|
+
/**
|
124
|
+
* Determines whether a parenthesized object literal that replaces a specified node needs to be preceded by a semicolon.
|
125
|
+
* @param {ASTNode} node The node to be replaced. This node should be at the start of an `ExpressionStatement` or at the start of the body of an `ArrowFunctionExpression`.
|
126
|
+
* @returns {boolean} Whether a semicolon is required before the parenthesized object literal.
|
127
|
+
*/
|
128
|
+
function needsSemicolon(node) {
|
129
|
+
const prevToken = sourceCode.getTokenBefore(node);
|
130
|
+
|
131
|
+
if (!prevToken || prevToken.type === "Punctuator" && PUNCTUATORS.has(prevToken.value)) {
|
132
|
+
return false;
|
133
|
+
}
|
134
|
+
|
135
|
+
const prevNode = sourceCode.getNodeByRangeIndex(prevToken.range[0]);
|
136
|
+
|
137
|
+
if (isClosingParenToken(prevToken)) {
|
138
|
+
return !STATEMENTS.has(prevNode.type);
|
139
|
+
}
|
140
|
+
|
141
|
+
if (isClosingBraceToken(prevToken)) {
|
142
|
+
return (
|
143
|
+
prevNode.type === "BlockStatement" && prevNode.parent.type === "FunctionExpression" ||
|
144
|
+
prevNode.type === "ClassBody" && prevNode.parent.type === "ClassExpression" ||
|
145
|
+
prevNode.type === "ObjectExpression"
|
146
|
+
);
|
147
|
+
}
|
148
|
+
|
149
|
+
if (IDENTIFIER_OR_KEYWORD.has(prevToken.type)) {
|
150
|
+
if (BREAK_OR_CONTINUE.has(prevNode.parent.type)) {
|
151
|
+
return false;
|
152
|
+
}
|
153
|
+
|
154
|
+
const keyword = prevToken.value;
|
155
|
+
const nodeType = NODE_TYPES_BY_KEYWORD[keyword];
|
156
|
+
|
157
|
+
return prevNode.type !== nodeType;
|
158
|
+
}
|
159
|
+
|
160
|
+
if (prevToken.type === "String") {
|
161
|
+
return !DECLARATIONS.has(prevNode.parent.type);
|
162
|
+
}
|
163
|
+
|
164
|
+
return true;
|
165
|
+
}
|
166
|
+
|
83
167
|
/**
|
84
168
|
* Reports on nodes where the `Object` constructor is called without arguments.
|
85
169
|
* @param {ASTNode} node The node to evaluate.
|
@@ -93,16 +177,30 @@ module.exports = {
|
|
93
177
|
const variable = getVariableByName(sourceCode.getScope(node), "Object");
|
94
178
|
|
95
179
|
if (variable && variable.identifiers.length === 0) {
|
96
|
-
|
180
|
+
let replacement;
|
181
|
+
let fixText;
|
182
|
+
let messageId = "useLiteral";
|
183
|
+
|
184
|
+
if (needsParentheses(node)) {
|
185
|
+
replacement = "({})";
|
186
|
+
if (needsSemicolon(node)) {
|
187
|
+
fixText = ";({})";
|
188
|
+
messageId = "useLiteralAfterSemicolon";
|
189
|
+
} else {
|
190
|
+
fixText = "({})";
|
191
|
+
}
|
192
|
+
} else {
|
193
|
+
replacement = fixText = "{}";
|
194
|
+
}
|
97
195
|
|
98
196
|
context.report({
|
99
197
|
node,
|
100
198
|
messageId: "preferLiteral",
|
101
199
|
suggest: [
|
102
200
|
{
|
103
|
-
messageId
|
201
|
+
messageId,
|
104
202
|
data: { replacement },
|
105
|
-
fix: fixer => fixer.replaceText(node,
|
203
|
+
fix: fixer => fixer.replaceText(node, fixText)
|
106
204
|
}
|
107
205
|
]
|
108
206
|
});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.52.0",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"bin": {
|
@@ -63,10 +63,11 @@
|
|
63
63
|
"@eslint-community/eslint-utils": "^4.2.0",
|
64
64
|
"@eslint-community/regexpp": "^4.6.1",
|
65
65
|
"@eslint/eslintrc": "^2.1.2",
|
66
|
-
"@eslint/js": "8.
|
67
|
-
"@humanwhocodes/config-array": "^0.11.
|
66
|
+
"@eslint/js": "8.52.0",
|
67
|
+
"@humanwhocodes/config-array": "^0.11.13",
|
68
68
|
"@humanwhocodes/module-importer": "^1.0.1",
|
69
69
|
"@nodelib/fs.walk": "^1.2.8",
|
70
|
+
"@ungap/structured-clone": "^1.2.0",
|
70
71
|
"ajv": "^6.12.4",
|
71
72
|
"chalk": "^4.0.0",
|
72
73
|
"cross-spawn": "^7.0.2",
|