eslint 8.37.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 +1 -11
- package/lib/linter/linter.js +3 -51
- package/lib/rules/block-scoped-var.js +2 -1
- package/lib/rules/camelcase.js +2 -2
- package/lib/rules/func-names.js +1 -1
- package/lib/rules/global-require.js +1 -1
- package/lib/rules/new-parens.js +5 -14
- package/lib/rules/no-class-assign.js +3 -1
- package/lib/rules/no-const-assign.js +3 -1
- package/lib/rules/no-div-regex.js +1 -1
- package/lib/rules/no-dupe-args.js +3 -1
- package/lib/rules/no-ex-assign.js +3 -1
- package/lib/rules/no-func-assign.js +3 -1
- package/lib/rules/no-import-assign.js +1 -1
- package/lib/rules/no-lone-blocks.js +5 -4
- package/lib/rules/no-lonely-if.js +2 -3
- package/lib/rules/no-param-reassign.js +2 -1
- package/lib/rules/no-restricted-exports.js +2 -1
- package/lib/rules/no-shadow-restricted-names.js +2 -1
- package/lib/rules/no-underscore-dangle.js +2 -1
- package/lib/rules/no-unused-expressions.js +4 -5
- package/lib/rules/no-unused-vars.js +1 -1
- package/lib/rules/no-var.js +2 -2
- package/lib/rules/prefer-arrow-callback.js +1 -1
- package/lib/rules/prefer-const.js +1 -1
- package/lib/rules/prefer-object-spread.js +0 -1
- package/lib/rules/prefer-promise-reject-errors.js +2 -1
- package/lib/rules/require-unicode-regexp.js +4 -0
- package/lib/rules/valid-typeof.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 +85 -0
- package/lib/source-code/token-store/utils.js +21 -16
- package/package.json +3 -3
package/README.md
CHANGED
@@ -244,20 +244,10 @@ The people who review and fix bugs and help triage issues.
|
|
244
244
|
Bryan Mishkin
|
245
245
|
</a>
|
246
246
|
</td><td align="center" valign="top" width="11%">
|
247
|
-
<a href="https://github.com/btmills">
|
248
|
-
<img src="https://github.com/btmills.png?s=75" width="75" height="75"><br />
|
249
|
-
Brandon Mills
|
250
|
-
</a>
|
251
|
-
</td><td align="center" valign="top" width="11%">
|
252
247
|
<a href="https://github.com/fasttime">
|
253
248
|
<img src="https://github.com/fasttime.png?s=75" width="75" height="75"><br />
|
254
249
|
Francesco Trotta
|
255
250
|
</a>
|
256
|
-
</td><td align="center" valign="top" width="11%">
|
257
|
-
<a href="https://github.com/yeonjuan">
|
258
|
-
<img src="https://github.com/yeonjuan.png?s=75" width="75" height="75"><br />
|
259
|
-
YeonJuan
|
260
|
-
</a>
|
261
251
|
</td></tr></tbody></table>
|
262
252
|
|
263
253
|
### Website Team
|
@@ -293,7 +283,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
|
|
293
283
|
<p><a href="#"><img src="https://images.opencollective.com/2021-frameworks-fund/logo.png" alt="Chrome Frameworks Fund" height="undefined"></a> <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>
|
294
284
|
<p><a href="https://ridicorp.com/career/"><img src="https://images.opencollective.com/ridi-corporation/175dcf3/logo.png" alt="RIDI" height="96"></a> <a href="https://engineering.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></p><h3>Silver Sponsors</h3>
|
295
285
|
<p><a href="https://sentry.io"><img src="https://avatars.githubusercontent.com/u/1396951?v=4" alt="Sentry" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="64"></a></p><h3>Bronze Sponsors</h3>
|
296
|
-
<p><a href="https://paydaysay.com/"><img src="https://images.opencollective.com/payday-say-organization/9cd2467/logo.png" alt="PayDay Say" 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://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://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://transloadit.com/"><img src="https://avatars.githubusercontent.com/u/125754?v=4" alt="Transloadit" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://quickbookstoolhub.com"><img src="https://avatars.githubusercontent.com/u/95090305?u=e5bc398ef775c9ed19f955c675cdc1fb6abf01df&v=4" alt="QuickBooks Tool hub" height="32"></a></p>
|
286
|
+
<p><a href="https://twicsy.com/buy-instagram-likes"><img src="https://images.opencollective.com/twicsy/7af290f/avatar.png" alt="Twicsy" height="32"></a> <a href="https://paydaysay.com/"><img src="https://images.opencollective.com/payday-say-organization/9cd2467/logo.png" alt="PayDay Say" 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://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://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://transloadit.com/"><img src="https://avatars.githubusercontent.com/u/125754?v=4" alt="Transloadit" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://quickbookstoolhub.com"><img src="https://avatars.githubusercontent.com/u/95090305?u=e5bc398ef775c9ed19f955c675cdc1fb6abf01df&v=4" alt="QuickBooks Tool hub" height="32"></a></p>
|
297
287
|
<!--sponsorsend-->
|
298
288
|
|
299
289
|
## Technology Sponsors
|
package/lib/linter/linter.js
CHANGED
@@ -857,38 +857,6 @@ function parse(text, languageOptions, filePath) {
|
|
857
857
|
}
|
858
858
|
}
|
859
859
|
|
860
|
-
/**
|
861
|
-
* Marks a variable as used in the current scope
|
862
|
-
* @param {SourceCode} sourceCode The source code for the currently linted file.
|
863
|
-
* @param {ASTNode} currentNode The node currently being traversed
|
864
|
-
* @param {LanguageOptions} languageOptions The options used to parse this text
|
865
|
-
* @param {string} name The name of the variable that should be marked as used.
|
866
|
-
* @returns {boolean} True if the variable was found and marked as used, false if not.
|
867
|
-
*/
|
868
|
-
function markVariableAsUsed(sourceCode, currentNode, languageOptions, name) {
|
869
|
-
const parserOptions = languageOptions.parserOptions;
|
870
|
-
const sourceType = languageOptions.sourceType;
|
871
|
-
const hasGlobalReturn =
|
872
|
-
(parserOptions.ecmaFeatures && parserOptions.ecmaFeatures.globalReturn) ||
|
873
|
-
sourceType === "commonjs";
|
874
|
-
const specialScope = hasGlobalReturn || sourceType === "module";
|
875
|
-
const currentScope = sourceCode.getScope(currentNode);
|
876
|
-
|
877
|
-
// Special Node.js scope means we need to start one level deeper
|
878
|
-
const initialScope = currentScope.type === "global" && specialScope ? currentScope.childScopes[0] : currentScope;
|
879
|
-
|
880
|
-
for (let scope = initialScope; scope; scope = scope.upper) {
|
881
|
-
const variable = scope.variables.find(scopeVar => scopeVar.name === name);
|
882
|
-
|
883
|
-
if (variable) {
|
884
|
-
variable.eslintUsed = true;
|
885
|
-
return true;
|
886
|
-
}
|
887
|
-
}
|
888
|
-
|
889
|
-
return false;
|
890
|
-
}
|
891
|
-
|
892
860
|
/**
|
893
861
|
* Runs a rule, and gets its listeners
|
894
862
|
* @param {Rule} rule A normalized rule with a `create` method
|
@@ -905,22 +873,6 @@ function createRuleListeners(rule, ruleContext) {
|
|
905
873
|
}
|
906
874
|
}
|
907
875
|
|
908
|
-
/**
|
909
|
-
* Gets all the ancestors of a given node
|
910
|
-
* @param {ASTNode} node The node
|
911
|
-
* @returns {ASTNode[]} All the ancestor nodes in the AST, not including the provided node, starting
|
912
|
-
* from the root node and going inwards to the parent node.
|
913
|
-
*/
|
914
|
-
function getAncestors(node) {
|
915
|
-
const ancestorsStartingAtParent = [];
|
916
|
-
|
917
|
-
for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
|
918
|
-
ancestorsStartingAtParent.push(ancestor);
|
919
|
-
}
|
920
|
-
|
921
|
-
return ancestorsStartingAtParent.reverse();
|
922
|
-
}
|
923
|
-
|
924
876
|
// methods that exist on SourceCode object
|
925
877
|
const DEPRECATED_SOURCECODE_PASSTHROUGHS = {
|
926
878
|
getSource: "getText",
|
@@ -996,14 +948,14 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO
|
|
996
948
|
Object.assign(
|
997
949
|
Object.create(BASE_TRAVERSAL_CONTEXT),
|
998
950
|
{
|
999
|
-
getAncestors: () => getAncestors(currentNode),
|
1000
|
-
getDeclaredVariables: sourceCode.
|
951
|
+
getAncestors: () => sourceCode.getAncestors(currentNode),
|
952
|
+
getDeclaredVariables: node => sourceCode.getDeclaredVariables(node),
|
1001
953
|
getCwd: () => cwd,
|
1002
954
|
getFilename: () => filename,
|
1003
955
|
getPhysicalFilename: () => physicalFilename || filename,
|
1004
956
|
getScope: () => sourceCode.getScope(currentNode),
|
1005
957
|
getSourceCode: () => sourceCode,
|
1006
|
-
markVariableAsUsed: name => markVariableAsUsed(
|
958
|
+
markVariableAsUsed: name => sourceCode.markVariableAsUsed(name, currentNode),
|
1007
959
|
parserOptions: {
|
1008
960
|
...languageOptions.parserOptions
|
1009
961
|
},
|
@@ -28,6 +28,7 @@ module.exports = {
|
|
28
28
|
|
29
29
|
create(context) {
|
30
30
|
let stack = [];
|
31
|
+
const sourceCode = context.getSourceCode();
|
31
32
|
|
32
33
|
/**
|
33
34
|
* Makes a block scope.
|
@@ -83,7 +84,7 @@ module.exports = {
|
|
83
84
|
}
|
84
85
|
|
85
86
|
// Gets declared variables, and checks its references.
|
86
|
-
const variables =
|
87
|
+
const variables = sourceCode.getDeclaredVariables(node);
|
87
88
|
|
88
89
|
for (let i = 0; i < variables.length; ++i) {
|
89
90
|
|
package/lib/rules/camelcase.js
CHANGED
@@ -296,7 +296,7 @@ module.exports = {
|
|
296
296
|
"ClassExpression",
|
297
297
|
"CatchClause"
|
298
298
|
]](node) {
|
299
|
-
for (const variable of
|
299
|
+
for (const variable of sourceCode.getDeclaredVariables(node)) {
|
300
300
|
if (isGoodName(variable.name)) {
|
301
301
|
continue;
|
302
302
|
}
|
@@ -346,7 +346,7 @@ module.exports = {
|
|
346
346
|
|
347
347
|
// Report camelcase in import --------------------------------------
|
348
348
|
ImportDeclaration(node) {
|
349
|
-
for (const variable of
|
349
|
+
for (const variable of sourceCode.getDeclaredVariables(node)) {
|
350
350
|
if (isGoodName(variable.name)) {
|
351
351
|
continue;
|
352
352
|
}
|
package/lib/rules/func-names.js
CHANGED
@@ -159,7 +159,7 @@ module.exports = {
|
|
159
159
|
function handleFunction(node) {
|
160
160
|
|
161
161
|
// Skip recursive functions.
|
162
|
-
const nameVar =
|
162
|
+
const nameVar = sourceCode.getDeclaredVariables(node)[0];
|
163
163
|
|
164
164
|
if (isFunctionName(nameVar) && nameVar.references.length > 0) {
|
165
165
|
return;
|
@@ -78,7 +78,7 @@ module.exports = {
|
|
78
78
|
const currentScope = sourceCode.getScope(node);
|
79
79
|
|
80
80
|
if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) {
|
81
|
-
const isGoodRequire =
|
81
|
+
const isGoodRequire = sourceCode.getAncestors(node).every(parent => ACCEPTABLE_PARENTS.has(parent.type));
|
82
82
|
|
83
83
|
if (!isGoodRequire) {
|
84
84
|
context.report({ node, messageId: "unexpected" });
|
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."
|
@@ -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 {
|
@@ -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
|
};
|
@@ -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];
|
@@ -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
|
|
@@ -31,6 +31,8 @@ module.exports = {
|
|
31
31
|
|
32
32
|
create(context) {
|
33
33
|
|
34
|
+
const sourceCode = context.getSourceCode();
|
35
|
+
|
34
36
|
/**
|
35
37
|
* Reports a reference if is non initializer and writable.
|
36
38
|
* @param {References} references Collection of reference to check.
|
@@ -65,7 +67,7 @@ module.exports = {
|
|
65
67
|
* @returns {void}
|
66
68
|
*/
|
67
69
|
function checkForFunction(node) {
|
68
|
-
|
70
|
+
sourceCode.getDeclaredVariables(node).forEach(checkVariable);
|
69
71
|
}
|
70
72
|
|
71
73
|
return {
|
@@ -200,7 +200,7 @@ module.exports = {
|
|
200
200
|
ImportDeclaration(node) {
|
201
201
|
const scope = sourceCode.getScope(node);
|
202
202
|
|
203
|
-
for (const variable of
|
203
|
+
for (const variable of sourceCode.getDeclaredVariables(node)) {
|
204
204
|
const shouldCheckMembers = variable.defs.some(
|
205
205
|
d => d.node.type === "ImportNamespaceSpecifier"
|
206
206
|
);
|
@@ -68,14 +68,15 @@ module.exports = {
|
|
68
68
|
/**
|
69
69
|
* Checks the enclosing block of the current node for block-level bindings,
|
70
70
|
* and "marks it" as valid if any.
|
71
|
+
* @param {ASTNode} node The current node to check.
|
71
72
|
* @returns {void}
|
72
73
|
*/
|
73
|
-
function markLoneBlock() {
|
74
|
+
function markLoneBlock(node) {
|
74
75
|
if (loneBlocks.length === 0) {
|
75
76
|
return;
|
76
77
|
}
|
77
78
|
|
78
|
-
const block =
|
79
|
+
const block = node.parent;
|
79
80
|
|
80
81
|
if (loneBlocks[loneBlocks.length - 1] === block) {
|
81
82
|
loneBlocks.pop();
|
@@ -117,13 +118,13 @@ module.exports = {
|
|
117
118
|
|
118
119
|
ruleDef.VariableDeclaration = function(node) {
|
119
120
|
if (node.kind === "let" || node.kind === "const") {
|
120
|
-
markLoneBlock();
|
121
|
+
markLoneBlock(node);
|
121
122
|
}
|
122
123
|
};
|
123
124
|
|
124
125
|
ruleDef.FunctionDeclaration = function(node) {
|
125
126
|
if (sourceCode.getScope(node).isStrict) {
|
126
|
-
markLoneBlock();
|
127
|
+
markLoneBlock(node);
|
127
128
|
}
|
128
129
|
};
|
129
130
|
|
@@ -32,9 +32,8 @@ module.exports = {
|
|
32
32
|
|
33
33
|
return {
|
34
34
|
IfStatement(node) {
|
35
|
-
const
|
36
|
-
|
37
|
-
grandparent = ancestors.pop();
|
35
|
+
const parent = node.parent,
|
36
|
+
grandparent = parent.parent;
|
38
37
|
|
39
38
|
if (parent && parent.type === "BlockStatement" &&
|
40
39
|
parent.body.length === 1 && grandparent &&
|
@@ -70,6 +70,7 @@ module.exports = {
|
|
70
70
|
const props = context.options[0] && context.options[0].props;
|
71
71
|
const ignoredPropertyAssignmentsFor = context.options[0] && context.options[0].ignorePropertyModificationsFor || [];
|
72
72
|
const ignoredPropertyAssignmentsForRegex = context.options[0] && context.options[0].ignorePropertyModificationsForRegex || [];
|
73
|
+
const sourceCode = context.getSourceCode();
|
73
74
|
|
74
75
|
/**
|
75
76
|
* Checks whether or not the reference modifies properties of its variable.
|
@@ -214,7 +215,7 @@ module.exports = {
|
|
214
215
|
* @returns {void}
|
215
216
|
*/
|
216
217
|
function checkForFunction(node) {
|
217
|
-
|
218
|
+
sourceCode.getDeclaredVariables(node).forEach(checkVariable);
|
218
219
|
}
|
219
220
|
|
220
221
|
return {
|
@@ -99,6 +99,7 @@ module.exports = {
|
|
99
99
|
|
100
100
|
const restrictedNames = new Set(context.options[0] && context.options[0].restrictedNamedExports);
|
101
101
|
const restrictDefaultExports = context.options[0] && context.options[0].restrictDefaultExports;
|
102
|
+
const sourceCode = context.getSourceCode();
|
102
103
|
|
103
104
|
/**
|
104
105
|
* Checks and reports given exported name.
|
@@ -176,7 +177,7 @@ module.exports = {
|
|
176
177
|
if (declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration") {
|
177
178
|
checkExportedName(declaration.id);
|
178
179
|
} else if (declaration.type === "VariableDeclaration") {
|
179
|
-
|
180
|
+
sourceCode.getDeclaredVariables(declaration)
|
180
181
|
.map(v => v.defs.find(d => d.parent === declaration))
|
181
182
|
.map(d => d.name) // Identifier nodes
|
182
183
|
.forEach(checkExportedName);
|
@@ -43,10 +43,11 @@ module.exports = {
|
|
43
43
|
|
44
44
|
|
45
45
|
const RESTRICTED = new Set(["undefined", "NaN", "Infinity", "arguments", "eval"]);
|
46
|
+
const sourceCode = context.getSourceCode();
|
46
47
|
|
47
48
|
return {
|
48
49
|
"VariableDeclaration, :function, CatchClause"(node) {
|
49
|
-
for (const variable of
|
50
|
+
for (const variable of sourceCode.getDeclaredVariables(node)) {
|
50
51
|
if (variable.defs.length > 0 && RESTRICTED.has(variable.name) && !safelyShadowsUndefined(variable)) {
|
51
52
|
context.report({
|
52
53
|
node: variable.defs[0].name,
|
@@ -84,6 +84,7 @@ module.exports = {
|
|
84
84
|
const allowFunctionParams = typeof options.allowFunctionParams !== "undefined" ? options.allowFunctionParams : true;
|
85
85
|
const allowInArrayDestructuring = typeof options.allowInArrayDestructuring !== "undefined" ? options.allowInArrayDestructuring : true;
|
86
86
|
const allowInObjectDestructuring = typeof options.allowInObjectDestructuring !== "undefined" ? options.allowInObjectDestructuring : true;
|
87
|
+
const sourceCode = context.getSourceCode();
|
87
88
|
|
88
89
|
//-------------------------------------------------------------------------
|
89
90
|
// Helpers
|
@@ -213,7 +214,7 @@ module.exports = {
|
|
213
214
|
* @private
|
214
215
|
*/
|
215
216
|
function checkForDanglingUnderscoreInVariableExpression(node) {
|
216
|
-
|
217
|
+
sourceCode.getDeclaredVariables(node).forEach(variable => {
|
217
218
|
const definition = variable.defs.find(def => def.node === node);
|
218
219
|
const identifierNode = definition.name;
|
219
220
|
const identifier = identifierNode.name;
|
@@ -109,12 +109,11 @@ module.exports = {
|
|
109
109
|
/**
|
110
110
|
* Detect if a Node is a directive.
|
111
111
|
* @param {ASTNode} node any node
|
112
|
-
* @param {ASTNode[]} ancestors the given node's ancestors
|
113
112
|
* @returns {boolean} whether the given node is considered a directive in its current position
|
114
113
|
*/
|
115
|
-
function isDirective(node
|
116
|
-
const parent =
|
117
|
-
grandparent =
|
114
|
+
function isDirective(node) {
|
115
|
+
const parent = node.parent,
|
116
|
+
grandparent = parent.parent;
|
118
117
|
|
119
118
|
/**
|
120
119
|
* https://tc39.es/ecma262/#directive-prologue
|
@@ -180,7 +179,7 @@ module.exports = {
|
|
180
179
|
|
181
180
|
return {
|
182
181
|
ExpressionStatement(node) {
|
183
|
-
if (Checker.isDisallowed(node.expression) && !isDirective(node
|
182
|
+
if (Checker.isDisallowed(node.expression) && !isDirective(node)) {
|
184
183
|
context.report({ node, messageId: "unusedExpression" });
|
185
184
|
}
|
186
185
|
}
|
@@ -555,7 +555,7 @@ module.exports = {
|
|
555
555
|
*/
|
556
556
|
function isAfterLastUsedArg(variable) {
|
557
557
|
const def = variable.defs[0];
|
558
|
-
const params =
|
558
|
+
const params = sourceCode.getDeclaredVariables(def.node);
|
559
559
|
const posteriorParams = params.slice(params.indexOf(variable) + 1);
|
560
560
|
|
561
561
|
// If any used parameters occur after this parameter, do not report.
|
package/lib/rules/no-var.js
CHANGED
@@ -210,7 +210,7 @@ module.exports = {
|
|
210
210
|
if (!declarator.init) {
|
211
211
|
return false;
|
212
212
|
}
|
213
|
-
const variables =
|
213
|
+
const variables = sourceCode.getDeclaredVariables(declarator);
|
214
214
|
|
215
215
|
return variables.some(hasReferenceInTDZ(declarator.init));
|
216
216
|
}
|
@@ -268,7 +268,7 @@ module.exports = {
|
|
268
268
|
* @returns {boolean} `true` if it can fix the node.
|
269
269
|
*/
|
270
270
|
function canFix(node) {
|
271
|
-
const variables =
|
271
|
+
const variables = sourceCode.getDeclaredVariables(node);
|
272
272
|
const scopeNode = getScopeNode(node);
|
273
273
|
|
274
274
|
if (node.parent.type === "SwitchCase" ||
|
@@ -263,7 +263,7 @@ module.exports = {
|
|
263
263
|
}
|
264
264
|
|
265
265
|
// Skip recursive functions.
|
266
|
-
const nameVar =
|
266
|
+
const nameVar = sourceCode.getDeclaredVariables(node)[0];
|
267
267
|
|
268
268
|
if (isFunctionName(nameVar) && nameVar.references.length > 0) {
|
269
269
|
return;
|
@@ -493,7 +493,7 @@ module.exports = {
|
|
493
493
|
|
494
494
|
VariableDeclaration(node) {
|
495
495
|
if (node.kind === "let" && !isInitOfForStatement(node)) {
|
496
|
-
variables.push(...
|
496
|
+
variables.push(...sourceCode.getDeclaredVariables(node));
|
497
497
|
}
|
498
498
|
}
|
499
499
|
};
|
@@ -41,6 +41,7 @@ module.exports = {
|
|
41
41
|
create(context) {
|
42
42
|
|
43
43
|
const ALLOW_EMPTY_REJECT = context.options.length && context.options[0].allowEmptyReject;
|
44
|
+
const sourceCode = context.getSourceCode();
|
44
45
|
|
45
46
|
//----------------------------------------------------------------------
|
46
47
|
// Helpers
|
@@ -100,7 +101,7 @@ module.exports = {
|
|
100
101
|
node.arguments.length && astUtils.isFunction(node.arguments[0]) &&
|
101
102
|
node.arguments[0].params.length > 1 && node.arguments[0].params[1].type === "Identifier"
|
102
103
|
) {
|
103
|
-
|
104
|
+
sourceCode.getDeclaredVariables(node.arguments[0])
|
104
105
|
|
105
106
|
/*
|
106
107
|
* Find the first variable that matches the second parameter's name.
|
@@ -78,6 +78,10 @@ module.exports = {
|
|
78
78
|
|
79
79
|
for (const { node: refNode } of tracker.iterateGlobalReferences(trackMap)) {
|
80
80
|
const [patternNode, flagsNode] = refNode.arguments;
|
81
|
+
|
82
|
+
if (patternNode && patternNode.type === "SpreadElement") {
|
83
|
+
continue;
|
84
|
+
}
|
81
85
|
const pattern = getStringIfConstant(patternNode, scope);
|
82
86
|
const flags = getStringIfConstant(flagsNode, scope);
|
83
87
|
|
@@ -83,7 +83,7 @@ module.exports = {
|
|
83
83
|
|
84
84
|
UnaryExpression(node) {
|
85
85
|
if (isTypeofExpression(node)) {
|
86
|
-
const parent =
|
86
|
+
const { parent } = node;
|
87
87
|
|
88
88
|
if (parent.type === "BinaryExpression" && OPERATORS.has(parent.operator)) {
|
89
89
|
const sibling = parent.left === node ? parent.right : parent.left;
|
package/lib/rules/wrap-regex.js
CHANGED
@@ -40,10 +40,9 @@ module.exports = {
|
|
40
40
|
if (nodeType === "RegularExpression") {
|
41
41
|
const beforeToken = sourceCode.getTokenBefore(node);
|
42
42
|
const afterToken = sourceCode.getTokenAfter(node);
|
43
|
-
const
|
44
|
-
const grandparent = ancestors[ancestors.length - 1];
|
43
|
+
const { parent } = node;
|
45
44
|
|
46
|
-
if (
|
45
|
+
if (parent.type === "MemberExpression" && parent.object === node &&
|
47
46
|
!(beforeToken && beforeToken.value === "(" && afterToken && afterToken.value === ")")) {
|
48
47
|
context.report({
|
49
48
|
node,
|
package/lib/rules/yoda.js
CHANGED
@@ -343,7 +343,7 @@ module.exports = {
|
|
343
343
|
) &&
|
344
344
|
!(!isEqualityOperator(node.operator) && onlyEquality) &&
|
345
345
|
isComparisonOperator(node.operator) &&
|
346
|
-
!(exceptRange && isRangeTest(
|
346
|
+
!(exceptRange && isRangeTest(node.parent))
|
347
347
|
) {
|
348
348
|
context.report({
|
349
349
|
node,
|
@@ -14,6 +14,12 @@ const
|
|
14
14
|
astUtils = require("../shared/ast-utils"),
|
15
15
|
Traverser = require("../shared/traverser");
|
16
16
|
|
17
|
+
//------------------------------------------------------------------------------
|
18
|
+
// Type Definitions
|
19
|
+
//------------------------------------------------------------------------------
|
20
|
+
|
21
|
+
/** @typedef {import("eslint-scope").Variable} Variable */
|
22
|
+
|
17
23
|
//------------------------------------------------------------------------------
|
18
24
|
// Private
|
19
25
|
//------------------------------------------------------------------------------
|
@@ -639,6 +645,85 @@ class SourceCode extends TokenStore {
|
|
639
645
|
return this.scopeManager.scopes[0];
|
640
646
|
}
|
641
647
|
|
648
|
+
/**
|
649
|
+
* Get the variables that `node` defines.
|
650
|
+
* This is a convenience method that passes through
|
651
|
+
* to the same method on the `scopeManager`.
|
652
|
+
* @param {ASTNode} node The node for which the variables are obtained.
|
653
|
+
* @returns {Array<Variable>} An array of variable nodes representing
|
654
|
+
* the variables that `node` defines.
|
655
|
+
*/
|
656
|
+
getDeclaredVariables(node) {
|
657
|
+
return this.scopeManager.getDeclaredVariables(node);
|
658
|
+
}
|
659
|
+
|
660
|
+
/* eslint-disable class-methods-use-this -- node is owned by SourceCode */
|
661
|
+
/**
|
662
|
+
* Gets all the ancestors of a given node
|
663
|
+
* @param {ASTNode} node The node
|
664
|
+
* @returns {Array<ASTNode>} All the ancestor nodes in the AST, not including the provided node, starting
|
665
|
+
* from the root node at index 0 and going inwards to the parent node.
|
666
|
+
* @throws {TypeError} When `node` is missing.
|
667
|
+
*/
|
668
|
+
getAncestors(node) {
|
669
|
+
|
670
|
+
if (!node) {
|
671
|
+
throw new TypeError("Missing required argument: node.");
|
672
|
+
}
|
673
|
+
|
674
|
+
const ancestorsStartingAtParent = [];
|
675
|
+
|
676
|
+
for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
|
677
|
+
ancestorsStartingAtParent.push(ancestor);
|
678
|
+
}
|
679
|
+
|
680
|
+
return ancestorsStartingAtParent.reverse();
|
681
|
+
}
|
682
|
+
/* eslint-enable class-methods-use-this -- node is owned by SourceCode */
|
683
|
+
|
684
|
+
/**
|
685
|
+
* Marks a variable as used in the current scope
|
686
|
+
* @param {string} name The name of the variable to mark as used.
|
687
|
+
* @param {ASTNode} [refNode] The closest node to the variable reference.
|
688
|
+
* @returns {boolean} True if the variable was found and marked as used, false if not.
|
689
|
+
*/
|
690
|
+
markVariableAsUsed(name, refNode = this.ast) {
|
691
|
+
|
692
|
+
const currentScope = this.getScope(refNode);
|
693
|
+
let initialScope = currentScope;
|
694
|
+
|
695
|
+
/*
|
696
|
+
* When we are in an ESM or CommonJS module, we need to start searching
|
697
|
+
* from the top-level scope, not the global scope. For ESM the top-level
|
698
|
+
* scope is the module scope; for CommonJS the top-level scope is the
|
699
|
+
* outer function scope.
|
700
|
+
*
|
701
|
+
* Without this check, we might miss a variable declared with `var` at
|
702
|
+
* the top-level because it won't exist in the global scope.
|
703
|
+
*/
|
704
|
+
if (
|
705
|
+
currentScope.type === "global" &&
|
706
|
+
currentScope.childScopes.length > 0 &&
|
707
|
+
|
708
|
+
// top-level scopes refer to a `Program` node
|
709
|
+
currentScope.childScopes[0].block === this.ast
|
710
|
+
) {
|
711
|
+
initialScope = currentScope.childScopes[0];
|
712
|
+
}
|
713
|
+
|
714
|
+
for (let scope = initialScope; scope; scope = scope.upper) {
|
715
|
+
const variable = scope.variables.find(scopeVar => scopeVar.name === name);
|
716
|
+
|
717
|
+
if (variable) {
|
718
|
+
variable.eslintUsed = true;
|
719
|
+
return true;
|
720
|
+
}
|
721
|
+
}
|
722
|
+
|
723
|
+
return false;
|
724
|
+
}
|
725
|
+
|
726
|
+
|
642
727
|
}
|
643
728
|
|
644
729
|
module.exports = SourceCode;
|
@@ -4,20 +4,6 @@
|
|
4
4
|
*/
|
5
5
|
"use strict";
|
6
6
|
|
7
|
-
//------------------------------------------------------------------------------
|
8
|
-
// Helpers
|
9
|
-
//------------------------------------------------------------------------------
|
10
|
-
|
11
|
-
/**
|
12
|
-
* Gets `token.range[0]` from the given token.
|
13
|
-
* @param {Node|Token|Comment} token The token to get.
|
14
|
-
* @returns {number} The start location.
|
15
|
-
* @private
|
16
|
-
*/
|
17
|
-
function getStartLocation(token) {
|
18
|
-
return token.range[0];
|
19
|
-
}
|
20
|
-
|
21
7
|
//------------------------------------------------------------------------------
|
22
8
|
// Exports
|
23
9
|
//------------------------------------------------------------------------------
|
@@ -30,9 +16,28 @@ function getStartLocation(token) {
|
|
30
16
|
* @returns {number} The found index or `tokens.length`.
|
31
17
|
*/
|
32
18
|
exports.search = function search(tokens, location) {
|
33
|
-
|
19
|
+
for (let minIndex = 0, maxIndex = tokens.length - 1; minIndex <= maxIndex;) {
|
34
20
|
|
35
|
-
|
21
|
+
/*
|
22
|
+
* Calculate the index in the middle between minIndex and maxIndex.
|
23
|
+
* `| 0` is used to round a fractional value down to the nearest integer: this is similar to
|
24
|
+
* using `Math.trunc()` or `Math.floor()`, but performance tests have shown this method to
|
25
|
+
* be faster.
|
26
|
+
*/
|
27
|
+
const index = (minIndex + maxIndex) / 2 | 0;
|
28
|
+
const token = tokens[index];
|
29
|
+
const tokenStartLocation = token.range[0];
|
30
|
+
|
31
|
+
if (location <= tokenStartLocation) {
|
32
|
+
if (index === minIndex) {
|
33
|
+
return index;
|
34
|
+
}
|
35
|
+
maxIndex = index;
|
36
|
+
} else {
|
37
|
+
minIndex = index + 1;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
return tokens.length;
|
36
41
|
};
|
37
42
|
|
38
43
|
/**
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.39.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,7 +63,7 @@
|
|
63
63
|
"@eslint-community/eslint-utils": "^4.2.0",
|
64
64
|
"@eslint-community/regexpp": "^4.4.0",
|
65
65
|
"@eslint/eslintrc": "^2.0.2",
|
66
|
-
"@eslint/js": "8.
|
66
|
+
"@eslint/js": "8.39.0",
|
67
67
|
"@humanwhocodes/config-array": "^0.11.8",
|
68
68
|
"@humanwhocodes/module-importer": "^1.0.1",
|
69
69
|
"@nodelib/fs.walk": "^1.2.8",
|
@@ -73,7 +73,7 @@
|
|
73
73
|
"debug": "^4.3.2",
|
74
74
|
"doctrine": "^3.0.0",
|
75
75
|
"escape-string-regexp": "^4.0.0",
|
76
|
-
"eslint-scope": "^7.
|
76
|
+
"eslint-scope": "^7.2.0",
|
77
77
|
"eslint-visitor-keys": "^3.4.0",
|
78
78
|
"espree": "^9.5.1",
|
79
79
|
"esquery": "^1.4.2",
|