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 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
@@ -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.scopeManager.getDeclaredVariables.bind(sourceCode.scopeManager),
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(sourceCode, currentNode, languageOptions, name),
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 = context.getDeclaredVariables(node);
87
+ const variables = sourceCode.getDeclaredVariables(node);
87
88
 
88
89
  for (let i = 0; i < variables.length; ++i) {
89
90
 
@@ -296,7 +296,7 @@ module.exports = {
296
296
  "ClassExpression",
297
297
  "CatchClause"
298
298
  ]](node) {
299
- for (const variable of context.getDeclaredVariables(node)) {
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 context.getDeclaredVariables(node)) {
349
+ for (const variable of sourceCode.getDeclaredVariables(node)) {
350
350
  if (isGoodName(variable.name)) {
351
351
  continue;
352
352
  }
@@ -159,7 +159,7 @@ module.exports = {
159
159
  function handleFunction(node) {
160
160
 
161
161
  // Skip recursive functions.
162
- const nameVar = context.getDeclaredVariables(node)[0];
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 = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.has(parent.type));
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" });
@@ -31,20 +31,11 @@ module.exports = {
31
31
  },
32
32
 
33
33
  fixable: "code",
34
- schema: {
35
- anyOf: [
36
- {
37
- type: "array",
38
- items: [
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
- context.getDeclaredVariables(node).forEach(checkVariable);
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
- context.getDeclaredVariables(node).forEach(checkVariable);
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 division operators explicitly at the beginning of regular expressions",
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 = context.getDeclaredVariables(node);
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
- context.getDeclaredVariables(node).forEach(checkVariable);
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
- context.getDeclaredVariables(node).forEach(checkVariable);
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 context.getDeclaredVariables(node)) {
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 = context.getAncestors().pop();
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 ancestors = context.getAncestors(),
36
- parent = ancestors.pop(),
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
- context.getDeclaredVariables(node).forEach(checkVariable);
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
- context.getDeclaredVariables(declaration)
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 context.getDeclaredVariables(node)) {
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
- context.getDeclaredVariables(node).forEach(variable => {
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, ancestors) {
116
- const parent = ancestors[ancestors.length - 1],
117
- grandparent = ancestors[ancestors.length - 2];
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, context.getAncestors())) {
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 = context.getDeclaredVariables(def.node);
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.
@@ -210,7 +210,7 @@ module.exports = {
210
210
  if (!declarator.init) {
211
211
  return false;
212
212
  }
213
- const variables = context.getDeclaredVariables(declarator);
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 = context.getDeclaredVariables(node);
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 = context.getDeclaredVariables(node)[0];
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(...context.getDeclaredVariables(node));
496
+ variables.push(...sourceCode.getDeclaredVariables(node));
497
497
  }
498
498
  }
499
499
  };
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * @fileoverview Prefers object spread property over Object.assign
3
3
  * @author Sharmila Jesupaul
4
- * See LICENSE file in root directory for full license.
5
4
  */
6
5
 
7
6
  "use strict";
@@ -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
- context.getDeclaredVariables(node.arguments[0])
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 = context.getAncestors().pop();
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;
@@ -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 ancestors = context.getAncestors();
44
- const grandparent = ancestors[ancestors.length - 1];
43
+ const { parent } = node;
45
44
 
46
- if (grandparent.type === "MemberExpression" && grandparent.object === node &&
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(context.getAncestors().pop()))
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
- const index = tokens.findIndex(el => location <= getStartLocation(el));
19
+ for (let minIndex = 0, maxIndex = tokens.length - 1; minIndex <= maxIndex;) {
34
20
 
35
- return index === -1 ? tokens.length : index;
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.37.0",
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.37.0",
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.1.1",
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",