eslint 8.15.0 → 8.16.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 +1 -1
- package/lib/cli-engine/cli-engine.js +2 -4
- package/lib/cli-engine/lint-result-cache.js +1 -1
- 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 +7 -4
- package/lib/rules/global-require.js +3 -3
- package/lib/rules/indent-legacy.js +2 -2
- package/lib/rules/indent.js +1 -1
- 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/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-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 +6 -6
- 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-wrappers.js +1 -1
- 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 +1 -1
- package/lib/rules/no-unused-expressions.js +1 -1
- package/lib/rules/no-unused-vars.js +1 -1
- 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/package.json +21 -6
package/README.md
CHANGED
@@ -297,7 +297,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
|
|
297
297
|
<!--sponsorsstart-->
|
298
298
|
<h3>Platinum Sponsors</h3>
|
299
299
|
<p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
|
300
|
-
<p><a href="https://
|
300
|
+
<p><a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
|
301
301
|
<p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
|
302
302
|
<p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a></p>
|
303
303
|
<!--sponsorsend-->
|
@@ -366,9 +366,7 @@ function *iterateRuleDeprecationWarnings(usedConfigArrays) {
|
|
366
366
|
|
367
367
|
// Flatten used configs.
|
368
368
|
/** @type {ExtractedConfig[]} */
|
369
|
-
const configs =
|
370
|
-
...usedConfigArrays.map(getUsedExtractedConfigs)
|
371
|
-
);
|
369
|
+
const configs = usedConfigArrays.flatMap(getUsedExtractedConfigs);
|
372
370
|
|
373
371
|
// Traverse rule configs.
|
374
372
|
for (const config of configs) {
|
@@ -1023,7 +1021,7 @@ class CLIEngine {
|
|
1023
1021
|
let formatterPath;
|
1024
1022
|
|
1025
1023
|
// if there's a slash, then it's a file (TODO: this check seems dubious for scoped npm packages)
|
1026
|
-
if (!namespace && normalizedFormatName.
|
1024
|
+
if (!namespace && normalizedFormatName.includes("/")) {
|
1027
1025
|
formatterPath = path.resolve(cwd, normalizedFormatName);
|
1028
1026
|
} else {
|
1029
1027
|
try {
|
@@ -36,7 +36,7 @@ const invalidCacheStrategyErrorMessage = `Cache strategy must be one of: ${valid
|
|
36
36
|
*/
|
37
37
|
function isValidCacheStrategy(cacheStrategy) {
|
38
38
|
return (
|
39
|
-
validCacheStrategies.
|
39
|
+
validCacheStrategies.includes(cacheStrategy)
|
40
40
|
);
|
41
41
|
}
|
42
42
|
|
@@ -100,7 +100,7 @@ class CodePathSegment {
|
|
100
100
|
* @returns {boolean} `true` if the segment is coming from the end of a loop.
|
101
101
|
*/
|
102
102
|
isLoopedPrevSegment(segment) {
|
103
|
-
return this.internal.loopedPrevSegments.
|
103
|
+
return this.internal.loopedPrevSegments.includes(segment);
|
104
104
|
}
|
105
105
|
|
106
106
|
/**
|
@@ -212,7 +212,7 @@ class CodePath {
|
|
212
212
|
}
|
213
213
|
|
214
214
|
// Reset the flag of skipping if all branches have been skipped.
|
215
|
-
if (skippedSegment && segment.prevSegments.
|
215
|
+
if (skippedSegment && segment.prevSegments.includes(skippedSegment)) {
|
216
216
|
skippedSegment = null;
|
217
217
|
}
|
218
218
|
visited[segment.id] = true;
|
@@ -299,12 +299,12 @@ module.exports = {
|
|
299
299
|
* @private
|
300
300
|
*/
|
301
301
|
function checkPropertyDescriptor(node) {
|
302
|
-
const namesToCheck = node.properties
|
302
|
+
const namesToCheck = new Set(node.properties
|
303
303
|
.filter(p => p.type === "Property" && p.kind === "init" && !p.computed)
|
304
|
-
.map(({ key }) => key.name);
|
304
|
+
.map(({ key }) => key.name));
|
305
305
|
|
306
|
-
const hasGetter = namesToCheck.
|
307
|
-
const hasSetter = namesToCheck.
|
306
|
+
const hasGetter = namesToCheck.has("get");
|
307
|
+
const hasSetter = namesToCheck.has("set");
|
308
308
|
|
309
309
|
if (checkSetWithoutGet && hasSetter && !hasGetter) {
|
310
310
|
report(node, "missingGetter");
|
@@ -53,7 +53,7 @@ module.exports = {
|
|
53
53
|
if (!node.parent) {
|
54
54
|
return null;
|
55
55
|
}
|
56
|
-
if (types.
|
56
|
+
if (!types.includes(node.parent.type)) {
|
57
57
|
return findClosestParentOfType(node.parent, types);
|
58
58
|
}
|
59
59
|
return node.parent;
|
@@ -87,7 +87,7 @@ module.exports = {
|
|
87
87
|
* @returns {boolean} Whether or not this function matches our callback name.
|
88
88
|
*/
|
89
89
|
function isCallback(node) {
|
90
|
-
return containsOnlyIdentifiers(node.callee) && callbacks.
|
90
|
+
return containsOnlyIdentifiers(node.callee) && callbacks.includes(sourceCode.getText(node.callee));
|
91
91
|
}
|
92
92
|
|
93
93
|
/**
|
@@ -65,7 +65,7 @@ module.exports = {
|
|
65
65
|
function checkAssignment(node, name, value) {
|
66
66
|
const isThis = value.type === "ThisExpression";
|
67
67
|
|
68
|
-
if (aliases.
|
68
|
+
if (aliases.includes(name)) {
|
69
69
|
if (!isThis || node.operator && node.operator !== "=") {
|
70
70
|
reportBadAssignment(node, name);
|
71
71
|
}
|
@@ -76,7 +76,7 @@ module.exports = {
|
|
76
76
|
function checkComputedProperty(node, value) {
|
77
77
|
if (
|
78
78
|
validIdentifier.test(value) &&
|
79
|
-
(allowKeywords || keywords.
|
79
|
+
(allowKeywords || !keywords.includes(String(value))) &&
|
80
80
|
!(allowPattern && allowPattern.test(value))
|
81
81
|
) {
|
82
82
|
const formattedValue = node.property.type === "Literal" ? JSON.stringify(value) : `\`${value}\``;
|
@@ -142,7 +142,7 @@ module.exports = {
|
|
142
142
|
!allowKeywords &&
|
143
143
|
!node.computed &&
|
144
144
|
node.property.type === "Identifier" &&
|
145
|
-
keywords.
|
145
|
+
keywords.includes(String(node.property.name))
|
146
146
|
) {
|
147
147
|
context.report({
|
148
148
|
node: node.property,
|
@@ -191,10 +191,13 @@ module.exports = {
|
|
191
191
|
function getParenTokens(node) {
|
192
192
|
switch (node.type) {
|
193
193
|
case "NewExpression":
|
194
|
-
if (!node.arguments.length &&
|
195
|
-
|
196
|
-
|
197
|
-
|
194
|
+
if (!node.arguments.length &&
|
195
|
+
!(
|
196
|
+
astUtils.isOpeningParenToken(sourceCode.getLastToken(node, { skip: 1 })) &&
|
197
|
+
astUtils.isClosingParenToken(sourceCode.getLastToken(node)) &&
|
198
|
+
node.callee.range[1] < node.range[1]
|
199
|
+
)
|
200
|
+
) {
|
198
201
|
|
199
202
|
// If the NewExpression does not have parens (e.g. `new Foo`), return null.
|
200
203
|
return null;
|
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
"use strict";
|
8
8
|
|
9
|
-
const ACCEPTABLE_PARENTS = [
|
9
|
+
const ACCEPTABLE_PARENTS = new Set([
|
10
10
|
"AssignmentExpression",
|
11
11
|
"VariableDeclarator",
|
12
12
|
"MemberExpression",
|
@@ -16,7 +16,7 @@ const ACCEPTABLE_PARENTS = [
|
|
16
16
|
"Program",
|
17
17
|
"VariableDeclaration",
|
18
18
|
"ChainExpression"
|
19
|
-
];
|
19
|
+
]);
|
20
20
|
|
21
21
|
/**
|
22
22
|
* Finds the eslint-scope reference in the given scope.
|
@@ -75,7 +75,7 @@ module.exports = {
|
|
75
75
|
const currentScope = context.getScope();
|
76
76
|
|
77
77
|
if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) {
|
78
|
-
const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.
|
78
|
+
const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.has(parent.type));
|
79
79
|
|
80
80
|
if (!isGoodRequire) {
|
81
81
|
context.report({ node, messageId: "unexpected" });
|
@@ -753,7 +753,7 @@ module.exports = {
|
|
753
753
|
if (typeof options.CallExpression.arguments === "number") {
|
754
754
|
nodeIndent += options.CallExpression.arguments * indentSize;
|
755
755
|
} else if (options.CallExpression.arguments === "first") {
|
756
|
-
if (parent.arguments.
|
756
|
+
if (parent.arguments.includes(node)) {
|
757
757
|
nodeIndent = parent.arguments[0].loc.start.column;
|
758
758
|
}
|
759
759
|
} else {
|
@@ -840,7 +840,7 @@ module.exports = {
|
|
840
840
|
"IfStatement", "WhileStatement", "ForStatement", "ForInStatement", "ForOfStatement", "DoWhileStatement", "ClassDeclaration", "TryStatement"
|
841
841
|
];
|
842
842
|
|
843
|
-
if (node.parent && statementsWithProperties.
|
843
|
+
if (node.parent && statementsWithProperties.includes(node.parent.type) && isNodeBodyBlock(node)) {
|
844
844
|
indent = getNodeIndent(node.parent).goodChar;
|
845
845
|
} else if (node.parent && node.parent.type === "CatchClause") {
|
846
846
|
indent = getNodeIndent(node.parent.parent).goodChar;
|
package/lib/rules/indent.js
CHANGED
@@ -796,7 +796,7 @@ module.exports = {
|
|
796
796
|
let statement = node.parent && node.parent.parent;
|
797
797
|
|
798
798
|
while (
|
799
|
-
statement.type === "UnaryExpression" && ["!", "~", "+", "-"].
|
799
|
+
statement.type === "UnaryExpression" && ["!", "~", "+", "-"].includes(statement.operator) ||
|
800
800
|
statement.type === "AssignmentExpression" ||
|
801
801
|
statement.type === "LogicalExpression" ||
|
802
802
|
statement.type === "SequenceExpression" ||
|
package/lib/rules/jsx-quotes.js
CHANGED
@@ -70,7 +70,7 @@ module.exports = {
|
|
70
70
|
* @public
|
71
71
|
*/
|
72
72
|
function usesExpectedQuotes(node) {
|
73
|
-
return node.value.
|
73
|
+
return node.value.includes(setting.quote) || astUtils.isSurroundedBy(node.raw, setting.quote);
|
74
74
|
}
|
75
75
|
|
76
76
|
return {
|
@@ -141,7 +141,7 @@ module.exports = {
|
|
141
141
|
comments = sourceCode.getAllComments(),
|
142
142
|
commentLines = getCommentLineNums(comments),
|
143
143
|
emptyLines = getEmptyLineNums(lines),
|
144
|
-
commentAndEmptyLines = commentLines.concat(emptyLines);
|
144
|
+
commentAndEmptyLines = new Set(commentLines.concat(emptyLines));
|
145
145
|
|
146
146
|
/**
|
147
147
|
* Returns whether or not comments are on lines starting with or ending with code
|
@@ -393,7 +393,7 @@ module.exports = {
|
|
393
393
|
const nextTokenOrComment = sourceCode.getTokenAfter(token, { includeComments: true });
|
394
394
|
|
395
395
|
// check for newline before
|
396
|
-
if (!exceptionStartAllowed && before && !commentAndEmptyLines.
|
396
|
+
if (!exceptionStartAllowed && before && !commentAndEmptyLines.has(prevLineNum) &&
|
397
397
|
!(astUtils.isCommentToken(previousTokenOrComment) && astUtils.isTokenOnSameLine(previousTokenOrComment, token))) {
|
398
398
|
const lineStart = token.range[0] - token.loc.start.column;
|
399
399
|
const range = [lineStart, lineStart];
|
@@ -408,7 +408,7 @@ module.exports = {
|
|
408
408
|
}
|
409
409
|
|
410
410
|
// check for newline after
|
411
|
-
if (!exceptionEndAllowed && after && !commentAndEmptyLines.
|
411
|
+
if (!exceptionEndAllowed && after && !commentAndEmptyLines.has(nextLineNum) &&
|
412
412
|
!(astUtils.isCommentToken(nextTokenOrComment) && astUtils.isTokenOnSameLine(token, nextTokenOrComment))) {
|
413
413
|
context.report({
|
414
414
|
node: token,
|
package/lib/rules/max-lines.js
CHANGED
@@ -159,10 +159,10 @@ module.exports = {
|
|
159
159
|
if (skipComments) {
|
160
160
|
const comments = sourceCode.getAllComments();
|
161
161
|
|
162
|
-
const commentLines = comments.flatMap(getLinesWithoutCode);
|
162
|
+
const commentLines = new Set(comments.flatMap(getLinesWithoutCode));
|
163
163
|
|
164
164
|
lines = lines.filter(
|
165
|
-
l => !commentLines.
|
165
|
+
l => !commentLines.has(l.lineNumber)
|
166
166
|
);
|
167
167
|
}
|
168
168
|
|
package/lib/rules/no-bitwise.js
CHANGED
@@ -76,7 +76,7 @@ module.exports = {
|
|
76
76
|
* @returns {boolean} Whether or not the node has a bitwise operator.
|
77
77
|
*/
|
78
78
|
function hasBitwiseOperator(node) {
|
79
|
-
return BITWISE_OPERATORS.
|
79
|
+
return BITWISE_OPERATORS.includes(node.operator);
|
80
80
|
}
|
81
81
|
|
82
82
|
/**
|
@@ -85,7 +85,7 @@ module.exports = {
|
|
85
85
|
* @returns {boolean} Whether or not the node has a bitwise operator.
|
86
86
|
*/
|
87
87
|
function allowedOperator(node) {
|
88
|
-
return allowed.
|
88
|
+
return allowed.includes(node.operator);
|
89
89
|
}
|
90
90
|
|
91
91
|
/**
|
package/lib/rules/no-console.js
CHANGED
@@ -30,10 +30,12 @@ const collector = new (class {
|
|
30
30
|
}
|
31
31
|
}
|
32
32
|
|
33
|
-
collectControlChars(regexpStr) {
|
33
|
+
collectControlChars(regexpStr, flags) {
|
34
|
+
const uFlag = typeof flags === "string" && flags.includes("u");
|
35
|
+
|
34
36
|
try {
|
35
37
|
this._source = regexpStr;
|
36
|
-
this._validator.validatePattern(regexpStr); // Call onCharacter hook
|
38
|
+
this._validator.validatePattern(regexpStr, void 0, void 0, uFlag); // Call onCharacter hook
|
37
39
|
} catch {
|
38
40
|
|
39
41
|
// Ignore syntax errors in RegExp.
|
@@ -68,13 +70,15 @@ module.exports = {
|
|
68
70
|
|
69
71
|
/**
|
70
72
|
* Get the regex expression
|
71
|
-
* @param {ASTNode} node node to evaluate
|
72
|
-
* @returns {
|
73
|
+
* @param {ASTNode} node `Literal` node to evaluate
|
74
|
+
* @returns {{ pattern: string, flags: string | null } | null} Regex if found (the given node is either a regex literal
|
75
|
+
* or a string literal that is the pattern argument of a RegExp constructor call). Otherwise `null`. If flags cannot be determined,
|
76
|
+
* the `flags` property will be `null`.
|
73
77
|
* @private
|
74
78
|
*/
|
75
|
-
function
|
79
|
+
function getRegExp(node) {
|
76
80
|
if (node.regex) {
|
77
|
-
return node.regex
|
81
|
+
return node.regex;
|
78
82
|
}
|
79
83
|
if (typeof node.value === "string" &&
|
80
84
|
(node.parent.type === "NewExpression" || node.parent.type === "CallExpression") &&
|
@@ -82,7 +86,15 @@ module.exports = {
|
|
82
86
|
node.parent.callee.name === "RegExp" &&
|
83
87
|
node.parent.arguments[0] === node
|
84
88
|
) {
|
85
|
-
|
89
|
+
const pattern = node.value;
|
90
|
+
const flags =
|
91
|
+
node.parent.arguments.length > 1 &&
|
92
|
+
node.parent.arguments[1].type === "Literal" &&
|
93
|
+
typeof node.parent.arguments[1].value === "string"
|
94
|
+
? node.parent.arguments[1].value
|
95
|
+
: null;
|
96
|
+
|
97
|
+
return { pattern, flags };
|
86
98
|
}
|
87
99
|
|
88
100
|
return null;
|
@@ -90,10 +102,11 @@ module.exports = {
|
|
90
102
|
|
91
103
|
return {
|
92
104
|
Literal(node) {
|
93
|
-
const
|
105
|
+
const regExp = getRegExp(node);
|
94
106
|
|
95
|
-
if (
|
96
|
-
const
|
107
|
+
if (regExp) {
|
108
|
+
const { pattern, flags } = regExp;
|
109
|
+
const controlCharacters = collector.collectControlChars(pattern, flags);
|
97
110
|
|
98
111
|
if (controlCharacters.length > 0) {
|
99
112
|
context.report({
|
@@ -51,13 +51,13 @@ module.exports = {
|
|
51
51
|
const sourceCode = context.getSourceCode();
|
52
52
|
|
53
53
|
// Node types which have a test which will coerce values to booleans.
|
54
|
-
const BOOLEAN_NODE_TYPES = [
|
54
|
+
const BOOLEAN_NODE_TYPES = new Set([
|
55
55
|
"IfStatement",
|
56
56
|
"DoWhileStatement",
|
57
57
|
"WhileStatement",
|
58
58
|
"ConditionalExpression",
|
59
59
|
"ForStatement"
|
60
|
-
];
|
60
|
+
]);
|
61
61
|
|
62
62
|
/**
|
63
63
|
* Check if a node is a Boolean function or constructor.
|
@@ -95,7 +95,7 @@ module.exports = {
|
|
95
95
|
(isBooleanFunctionOrConstructorCall(node.parent) &&
|
96
96
|
node === node.parent.arguments[0]) ||
|
97
97
|
|
98
|
-
(BOOLEAN_NODE_TYPES.
|
98
|
+
(BOOLEAN_NODE_TYPES.has(node.parent.type) &&
|
99
99
|
node === node.parent.test) ||
|
100
100
|
|
101
101
|
// !<bool>
|
@@ -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
|
}
|
@@ -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));
|
@@ -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",
|
@@ -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
|
/**
|
@@ -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
|
|
package/lib/rules/quote-props.js
CHANGED
@@ -95,7 +95,7 @@ module.exports = {
|
|
95
95
|
* @returns {boolean} `true` if it is an ES3 token.
|
96
96
|
*/
|
97
97
|
function isKeyword(tokenStr) {
|
98
|
-
return keywords.
|
98
|
+
return keywords.includes(tokenStr);
|
99
99
|
}
|
100
100
|
|
101
101
|
/**
|
@@ -108,7 +108,7 @@ module.exports = {
|
|
108
108
|
*/
|
109
109
|
function areQuotesRedundant(rawKey, tokens, skipNumberLiterals) {
|
110
110
|
return tokens.length === 1 && tokens[0].start === 0 && tokens[0].end === rawKey.length &&
|
111
|
-
(["Identifier", "Keyword", "Null", "Boolean"].
|
111
|
+
(["Identifier", "Keyword", "Null", "Boolean"].includes(tokens[0].type) ||
|
112
112
|
(tokens[0].type === "Numeric" && !skipNumberLiterals && String(+tokens[0].value) === tokens[0].value));
|
113
113
|
}
|
114
114
|
|
package/lib/rules/quotes.js
CHANGED
@@ -283,7 +283,7 @@ module.exports = {
|
|
283
283
|
astUtils.isSurroundedBy(rawVal, settings.quote);
|
284
284
|
|
285
285
|
if (!isValid && avoidEscape) {
|
286
|
-
isValid = astUtils.isSurroundedBy(rawVal, settings.alternateQuote) && rawVal.
|
286
|
+
isValid = astUtils.isSurroundedBy(rawVal, settings.alternateQuote) && rawVal.includes(settings.quote);
|
287
287
|
}
|
288
288
|
|
289
289
|
if (!isValid) {
|
package/lib/rules/valid-jsdoc.js
CHANGED
@@ -42,8 +42,8 @@ module.exports = {
|
|
42
42
|
|
43
43
|
create(context) {
|
44
44
|
|
45
|
-
const VALID_TYPES = ["symbol", "undefined", "object", "boolean", "number", "string", "function", "bigint"],
|
46
|
-
OPERATORS = ["==", "===", "!=", "!=="];
|
45
|
+
const VALID_TYPES = new Set(["symbol", "undefined", "object", "boolean", "number", "string", "function", "bigint"]),
|
46
|
+
OPERATORS = new Set(["==", "===", "!=", "!=="]);
|
47
47
|
|
48
48
|
const requireStringLiterals = context.options[0] && context.options[0].requireStringLiterals;
|
49
49
|
|
@@ -85,13 +85,13 @@ module.exports = {
|
|
85
85
|
if (isTypeofExpression(node)) {
|
86
86
|
const parent = context.getAncestors().pop();
|
87
87
|
|
88
|
-
if (parent.type === "BinaryExpression" && OPERATORS.
|
88
|
+
if (parent.type === "BinaryExpression" && OPERATORS.has(parent.operator)) {
|
89
89
|
const sibling = parent.left === node ? parent.right : parent.left;
|
90
90
|
|
91
91
|
if (sibling.type === "Literal" || sibling.type === "TemplateLiteral" && !sibling.expressions.length) {
|
92
92
|
const value = sibling.type === "Literal" ? sibling.value : sibling.quasis[0].value.cooked;
|
93
93
|
|
94
|
-
if (VALID_TYPES.
|
94
|
+
if (!VALID_TYPES.has(value)) {
|
95
95
|
context.report({ node: sibling, messageId: "invalidValue" });
|
96
96
|
}
|
97
97
|
} else if (sibling.type === "Identifier" && sibling.name === "undefined" && isReferenceToGlobalVariable(sibling)) {
|
package/lib/rules/yoda.js
CHANGED
@@ -39,7 +39,7 @@ function isEqualityOperator(operator) {
|
|
39
39
|
* @returns {boolean} Whether the operator is used in range tests.
|
40
40
|
*/
|
41
41
|
function isRangeTestOperator(operator) {
|
42
|
-
return ["<", "<="].
|
42
|
+
return ["<", "<="].includes(operator);
|
43
43
|
}
|
44
44
|
|
45
45
|
/**
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.16.0",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"bin": {
|
@@ -25,14 +25,19 @@
|
|
25
25
|
"publish-release": "node Makefile.js publishRelease",
|
26
26
|
"gensite": "node Makefile.js gensite",
|
27
27
|
"webpack": "node Makefile.js webpack",
|
28
|
-
"perf": "node Makefile.js perf"
|
28
|
+
"perf": "node Makefile.js perf",
|
29
|
+
"docs:update-links": "node tools/fetch-docs-links.js"
|
29
30
|
},
|
30
31
|
"gitHooks": {
|
31
32
|
"pre-commit": "lint-staged"
|
32
33
|
},
|
33
34
|
"lint-staged": {
|
34
35
|
"*.js": "eslint --fix",
|
35
|
-
"*.md": "markdownlint --fix"
|
36
|
+
"*.md": "markdownlint --fix",
|
37
|
+
"docs/src/rules/*.md": [
|
38
|
+
"node tools/fetch-docs-links.js",
|
39
|
+
"git add docs/src/_data/further_reading_links.json"
|
40
|
+
]
|
36
41
|
},
|
37
42
|
"files": [
|
38
43
|
"LICENSE",
|
@@ -47,7 +52,7 @@
|
|
47
52
|
"homepage": "https://eslint.org",
|
48
53
|
"bugs": "https://github.com/eslint/eslint/issues/",
|
49
54
|
"dependencies": {
|
50
|
-
"@eslint/eslintrc": "^1.
|
55
|
+
"@eslint/eslintrc": "^1.3.0",
|
51
56
|
"@humanwhocodes/config-array": "^0.9.2",
|
52
57
|
"ajv": "^6.10.0",
|
53
58
|
"chalk": "^4.0.0",
|
@@ -65,7 +70,7 @@
|
|
65
70
|
"file-entry-cache": "^6.0.1",
|
66
71
|
"functional-red-black-tree": "^1.0.1",
|
67
72
|
"glob-parent": "^6.0.1",
|
68
|
-
"globals": "^13.
|
73
|
+
"globals": "^13.15.0",
|
69
74
|
"ignore": "^5.2.0",
|
70
75
|
"import-fresh": "^3.0.0",
|
71
76
|
"imurmurhash": "^0.1.4",
|
@@ -96,15 +101,19 @@
|
|
96
101
|
"eslint": "file:.",
|
97
102
|
"eslint-config-eslint": "file:packages/eslint-config-eslint",
|
98
103
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
99
|
-
"eslint-plugin-eslint-plugin": "^4.0
|
104
|
+
"eslint-plugin-eslint-plugin": "^4.2.0",
|
100
105
|
"eslint-plugin-internal-rules": "file:tools/internal-rules",
|
101
106
|
"eslint-plugin-jsdoc": "^37.0.0",
|
102
107
|
"eslint-plugin-node": "^11.1.0",
|
108
|
+
"eslint-plugin-unicorn": "^42.0.0",
|
103
109
|
"eslint-release": "^3.2.0",
|
104
110
|
"eslump": "^3.0.0",
|
105
111
|
"esprima": "^4.0.1",
|
112
|
+
"fast-glob": "^3.2.11",
|
106
113
|
"fs-teardown": "^0.1.3",
|
107
114
|
"glob": "^7.1.6",
|
115
|
+
"got": "^11.8.3",
|
116
|
+
"gray-matter": "^4.0.3",
|
108
117
|
"jsdoc": "^3.5.5",
|
109
118
|
"karma": "^6.1.1",
|
110
119
|
"karma-chrome-launcher": "^3.1.0",
|
@@ -117,6 +126,12 @@
|
|
117
126
|
"markdownlint-cli": "^0.30.0",
|
118
127
|
"marked": "^4.0.8",
|
119
128
|
"memfs": "^3.0.1",
|
129
|
+
"metascraper": "^5.25.7",
|
130
|
+
"metascraper-description": "^5.25.7",
|
131
|
+
"metascraper-image": "^5.29.3",
|
132
|
+
"metascraper-logo": "^5.25.7",
|
133
|
+
"metascraper-logo-favicon": "^5.25.7",
|
134
|
+
"metascraper-title": "^5.25.7",
|
120
135
|
"mocha": "^8.3.2",
|
121
136
|
"mocha-junit-reporter": "^2.0.0",
|
122
137
|
"node-polyfill-webpack-plugin": "^1.0.3",
|