eslint 9.25.1 → 9.27.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.
Files changed (40) hide show
  1. package/README.md +44 -39
  2. package/bin/eslint.js +15 -0
  3. package/conf/rule-type-list.json +2 -1
  4. package/lib/cli-engine/cli-engine.js +8 -8
  5. package/lib/cli.js +6 -5
  6. package/lib/config/config-loader.js +10 -18
  7. package/lib/config/config.js +328 -5
  8. package/lib/eslint/eslint-helpers.js +3 -1
  9. package/lib/eslint/eslint.js +31 -17
  10. package/lib/eslint/legacy-eslint.js +7 -7
  11. package/lib/languages/js/index.js +4 -3
  12. package/lib/languages/js/source-code/source-code.js +10 -6
  13. package/lib/linter/apply-disable-directives.js +1 -1
  14. package/lib/linter/esquery.js +329 -0
  15. package/lib/linter/file-context.js +11 -0
  16. package/lib/linter/linter.js +81 -89
  17. package/lib/linter/node-event-generator.js +94 -251
  18. package/lib/linter/report-translator.js +2 -1
  19. package/lib/options.js +11 -0
  20. package/lib/rule-tester/rule-tester.js +17 -9
  21. package/lib/rules/eqeqeq.js +31 -8
  22. package/lib/rules/index.js +2 -1
  23. package/lib/rules/max-params.js +32 -7
  24. package/lib/rules/no-array-constructor.js +51 -1
  25. package/lib/rules/no-shadow-restricted-names.js +25 -2
  26. package/lib/rules/no-unassigned-vars.js +72 -0
  27. package/lib/rules/no-unused-expressions.js +7 -1
  28. package/lib/rules/no-useless-escape.js +24 -2
  29. package/lib/rules/prefer-named-capture-group.js +7 -1
  30. package/lib/rules/utils/lazy-loading-rule-map.js +2 -2
  31. package/lib/services/processor-service.js +1 -2
  32. package/lib/services/suppressions-service.js +5 -3
  33. package/lib/shared/flags.js +1 -0
  34. package/lib/shared/serialization.js +29 -6
  35. package/lib/types/index.d.ts +126 -6
  36. package/lib/types/rules.d.ts +33 -2
  37. package/package.json +7 -6
  38. package/lib/config/flat-config-helpers.js +0 -128
  39. package/lib/config/rule-validator.js +0 -199
  40. package/lib/shared/types.js +0 -246
@@ -9,248 +9,28 @@
9
9
  // Requirements
10
10
  //------------------------------------------------------------------------------
11
11
 
12
- const esquery = require("esquery");
12
+ const { parse, matches } = require("./esquery");
13
13
 
14
- //------------------------------------------------------------------------------
14
+ //-----------------------------------------------------------------------------
15
15
  // Typedefs
16
- //------------------------------------------------------------------------------
16
+ //-----------------------------------------------------------------------------
17
17
 
18
18
  /**
19
- * An object describing an AST selector
20
- * @typedef {Object} ASTSelector
21
- * @property {string} rawSelector The string that was parsed into this selector
22
- * @property {boolean} isExit `true` if this should be emitted when exiting the node rather than when entering
23
- * @property {Object} parsedSelector An object (from esquery) describing the matching behavior of the selector
24
- * @property {string[]|null} listenerTypes A list of node types that could possibly cause the selector to match,
25
- * or `null` if all node types could cause a match
26
- * @property {number} attributeCount The total number of classes, pseudo-classes, and attribute queries in this selector
27
- * @property {number} identifierCount The total number of identifier queries in this selector
19
+ * @import { ESQueryParsedSelector } from "./esquery.js";
28
20
  */
29
21
 
30
- //------------------------------------------------------------------------------
22
+ //-----------------------------------------------------------------------------
31
23
  // Helpers
32
- //------------------------------------------------------------------------------
33
-
34
- /**
35
- * Computes the union of one or more arrays
36
- * @param {...any[]} arrays One or more arrays to union
37
- * @returns {any[]} The union of the input arrays
38
- */
39
- function union(...arrays) {
40
- return [...new Set(arrays.flat())];
41
- }
42
-
43
- /**
44
- * Computes the intersection of one or more arrays
45
- * @param {...any[]} arrays One or more arrays to intersect
46
- * @returns {any[]} The intersection of the input arrays
47
- */
48
- function intersection(...arrays) {
49
- if (arrays.length === 0) {
50
- return [];
51
- }
52
-
53
- let result = [...new Set(arrays[0])];
54
-
55
- for (const array of arrays.slice(1)) {
56
- result = result.filter(x => array.includes(x));
57
- }
58
- return result;
59
- }
60
-
61
- /**
62
- * Gets the possible types of a selector
63
- * @param {Object} parsedSelector An object (from esquery) describing the matching behavior of the selector
64
- * @returns {string[]|null} The node types that could possibly trigger this selector, or `null` if all node types could trigger it
65
- */
66
- function getPossibleTypes(parsedSelector) {
67
- switch (parsedSelector.type) {
68
- case "identifier":
69
- return [parsedSelector.value];
70
-
71
- case "matches": {
72
- const typesForComponents =
73
- parsedSelector.selectors.map(getPossibleTypes);
74
-
75
- if (typesForComponents.every(Boolean)) {
76
- return union(...typesForComponents);
77
- }
78
- return null;
79
- }
80
-
81
- case "compound": {
82
- const typesForComponents = parsedSelector.selectors
83
- .map(getPossibleTypes)
84
- .filter(typesForComponent => typesForComponent);
85
-
86
- // If all of the components could match any type, then the compound could also match any type.
87
- if (!typesForComponents.length) {
88
- return null;
89
- }
90
-
91
- /*
92
- * If at least one of the components could only match a particular type, the compound could only match
93
- * the intersection of those types.
94
- */
95
- return intersection(...typesForComponents);
96
- }
97
-
98
- case "child":
99
- case "descendant":
100
- case "sibling":
101
- case "adjacent":
102
- return getPossibleTypes(parsedSelector.right);
103
-
104
- case "class":
105
- if (parsedSelector.name === "function") {
106
- return [
107
- "FunctionDeclaration",
108
- "FunctionExpression",
109
- "ArrowFunctionExpression",
110
- ];
111
- }
112
-
113
- return null;
114
-
115
- default:
116
- return null;
117
- }
118
- }
119
-
120
- /**
121
- * Counts the number of class, pseudo-class, and attribute queries in this selector
122
- * @param {Object} parsedSelector An object (from esquery) describing the selector's matching behavior
123
- * @returns {number} The number of class, pseudo-class, and attribute queries in this selector
124
- */
125
- function countClassAttributes(parsedSelector) {
126
- switch (parsedSelector.type) {
127
- case "child":
128
- case "descendant":
129
- case "sibling":
130
- case "adjacent":
131
- return (
132
- countClassAttributes(parsedSelector.left) +
133
- countClassAttributes(parsedSelector.right)
134
- );
135
-
136
- case "compound":
137
- case "not":
138
- case "matches":
139
- return parsedSelector.selectors.reduce(
140
- (sum, childSelector) =>
141
- sum + countClassAttributes(childSelector),
142
- 0,
143
- );
144
-
145
- case "attribute":
146
- case "field":
147
- case "nth-child":
148
- case "nth-last-child":
149
- return 1;
150
-
151
- default:
152
- return 0;
153
- }
154
- }
155
-
156
- /**
157
- * Counts the number of identifier queries in this selector
158
- * @param {Object} parsedSelector An object (from esquery) describing the selector's matching behavior
159
- * @returns {number} The number of identifier queries
160
- */
161
- function countIdentifiers(parsedSelector) {
162
- switch (parsedSelector.type) {
163
- case "child":
164
- case "descendant":
165
- case "sibling":
166
- case "adjacent":
167
- return (
168
- countIdentifiers(parsedSelector.left) +
169
- countIdentifiers(parsedSelector.right)
170
- );
171
-
172
- case "compound":
173
- case "not":
174
- case "matches":
175
- return parsedSelector.selectors.reduce(
176
- (sum, childSelector) => sum + countIdentifiers(childSelector),
177
- 0,
178
- );
179
-
180
- case "identifier":
181
- return 1;
182
-
183
- default:
184
- return 0;
185
- }
186
- }
24
+ //-----------------------------------------------------------------------------
187
25
 
188
26
  /**
189
- * Compares the specificity of two selector objects, with CSS-like rules.
190
- * @param {ASTSelector} selectorA An AST selector descriptor
191
- * @param {ASTSelector} selectorB Another AST selector descriptor
192
- * @returns {number}
193
- * a value less than 0 if selectorA is less specific than selectorB
194
- * a value greater than 0 if selectorA is more specific than selectorB
195
- * a value less than 0 if selectorA and selectorB have the same specificity, and selectorA <= selectorB alphabetically
196
- * a value greater than 0 if selectorA and selectorB have the same specificity, and selectorA > selectorB alphabetically
27
+ * Compares two ESQuery selectors by specificity.
28
+ * @param {ESQueryParsedSelector} a The first selector to compare.
29
+ * @param {ESQueryParsedSelector} b The second selector to compare.
30
+ * @returns {number} A negative number if `a` is less specific than `b` or they are equally specific and `a` <= `b` alphabetically, a positive number if `a` is more specific than `b`.
197
31
  */
198
- function compareSpecificity(selectorA, selectorB) {
199
- return (
200
- selectorA.attributeCount - selectorB.attributeCount ||
201
- selectorA.identifierCount - selectorB.identifierCount ||
202
- (selectorA.rawSelector <= selectorB.rawSelector ? -1 : 1)
203
- );
204
- }
205
-
206
- /**
207
- * Parses a raw selector string, and throws a useful error if parsing fails.
208
- * @param {string} rawSelector A raw AST selector
209
- * @returns {Object} An object (from esquery) describing the matching behavior of this selector
210
- * @throws {Error} An error if the selector is invalid
211
- */
212
- function tryParseSelector(rawSelector) {
213
- try {
214
- return esquery.parse(rawSelector.replace(/:exit$/u, ""));
215
- } catch (err) {
216
- if (
217
- err.location &&
218
- err.location.start &&
219
- typeof err.location.start.offset === "number"
220
- ) {
221
- throw new SyntaxError(
222
- `Syntax error in selector "${rawSelector}" at position ${err.location.start.offset}: ${err.message}`,
223
- );
224
- }
225
- throw err;
226
- }
227
- }
228
-
229
- const selectorCache = new Map();
230
-
231
- /**
232
- * Parses a raw selector string, and returns the parsed selector along with specificity and type information.
233
- * @param {string} rawSelector A raw AST selector
234
- * @returns {ASTSelector} A selector descriptor
235
- */
236
- function parseSelector(rawSelector) {
237
- if (selectorCache.has(rawSelector)) {
238
- return selectorCache.get(rawSelector);
239
- }
240
-
241
- const parsedSelector = tryParseSelector(rawSelector);
242
-
243
- const result = {
244
- rawSelector,
245
- isExit: rawSelector.endsWith(":exit"),
246
- parsedSelector,
247
- listenerTypes: getPossibleTypes(parsedSelector),
248
- attributeCount: countClassAttributes(parsedSelector),
249
- identifierCount: countIdentifiers(parsedSelector),
250
- };
251
-
252
- selectorCache.set(rawSelector, result);
253
- return result;
32
+ function compareSpecificity(a, b) {
33
+ return a.compare(b);
254
34
  }
255
35
 
256
36
  //------------------------------------------------------------------------------
@@ -270,6 +50,52 @@ function parseSelector(rawSelector) {
270
50
  * ```
271
51
  */
272
52
  class NodeEventGenerator {
53
+ /**
54
+ * The emitter to use during traversal.
55
+ * @type {SafeEmitter}
56
+ */
57
+ emitter;
58
+
59
+ /**
60
+ * The options for `esquery` to use during matching.
61
+ * @type {ESQueryOptions}
62
+ */
63
+ esqueryOptions;
64
+
65
+ /**
66
+ * The ancestry of the currently visited node.
67
+ * @type {ASTNode[]}
68
+ */
69
+ currentAncestry = [];
70
+
71
+ /**
72
+ * A map of node type to selectors targeting that node type on the
73
+ * enter phase of traversal.
74
+ * @type {Map<string, ESQueryParsedSelector[]>}
75
+ */
76
+ enterSelectorsByNodeType = new Map();
77
+
78
+ /**
79
+ * A map of node type to selectors targeting that node type on the
80
+ * exit phase of traversal.
81
+ * @type {Map<string, ESQueryParsedSelector[]>}
82
+ */
83
+ exitSelectorsByNodeType = new Map();
84
+
85
+ /**
86
+ * An array of selectors that match any node type on the
87
+ * enter phase of traversal.
88
+ * @type {ESQueryParsedSelector[]}
89
+ */
90
+ anyTypeEnterSelectors = [];
91
+
92
+ /**
93
+ * An array of selectors that match any node type on the
94
+ * exit phase of traversal.
95
+ * @type {ESQueryParsedSelector[]}
96
+ */
97
+ anyTypeExitSelectors = [];
98
+
273
99
  /**
274
100
  * @param {SafeEmitter} emitter
275
101
  * An SafeEmitter which is the destination of events. This emitter must already
@@ -281,21 +107,20 @@ class NodeEventGenerator {
281
107
  constructor(emitter, esqueryOptions) {
282
108
  this.emitter = emitter;
283
109
  this.esqueryOptions = esqueryOptions;
284
- this.currentAncestry = [];
285
- this.enterSelectorsByNodeType = new Map();
286
- this.exitSelectorsByNodeType = new Map();
287
- this.anyTypeEnterSelectors = [];
288
- this.anyTypeExitSelectors = [];
289
110
 
290
111
  emitter.eventNames().forEach(rawSelector => {
291
- const selector = parseSelector(rawSelector);
112
+ const selector = parse(rawSelector);
292
113
 
293
- if (selector.listenerTypes) {
114
+ /*
115
+ * If this selector has identified specific node types,
116
+ * add it to the map for these node types for faster lookup.
117
+ */
118
+ if (selector.nodeTypes) {
294
119
  const typeMap = selector.isExit
295
120
  ? this.exitSelectorsByNodeType
296
121
  : this.enterSelectorsByNodeType;
297
122
 
298
- selector.listenerTypes.forEach(nodeType => {
123
+ selector.nodeTypes.forEach(nodeType => {
299
124
  if (!typeMap.has(nodeType)) {
300
125
  typeMap.set(nodeType, []);
301
126
  }
@@ -303,6 +128,13 @@ class NodeEventGenerator {
303
128
  });
304
129
  return;
305
130
  }
131
+
132
+ /*
133
+ * Remaining selectors are added to the "any type" selectors
134
+ * list for the appropriate phase of traversal. This ensures
135
+ * that all selectors will still be applied even if no
136
+ * specific node type is matched.
137
+ */
306
138
  const selectors = selector.isExit
307
139
  ? this.anyTypeExitSelectors
308
140
  : this.anyTypeEnterSelectors;
@@ -310,6 +142,7 @@ class NodeEventGenerator {
310
142
  selectors.push(selector);
311
143
  });
312
144
 
145
+ // sort all selectors by specificity for prioritizing call order
313
146
  this.anyTypeEnterSelectors.sort(compareSpecificity);
314
147
  this.anyTypeExitSelectors.sort(compareSpecificity);
315
148
  this.enterSelectorsByNodeType.forEach(selectorList =>
@@ -323,19 +156,19 @@ class NodeEventGenerator {
323
156
  /**
324
157
  * Checks a selector against a node, and emits it if it matches
325
158
  * @param {ASTNode} node The node to check
326
- * @param {ASTSelector} selector An AST selector descriptor
159
+ * @param {ESQueryParsedSelector} selector An AST selector descriptor
327
160
  * @returns {void}
328
161
  */
329
162
  applySelector(node, selector) {
330
163
  if (
331
- esquery.matches(
164
+ matches(
332
165
  node,
333
- selector.parsedSelector,
166
+ selector.root,
334
167
  this.currentAncestry,
335
168
  this.esqueryOptions,
336
169
  )
337
170
  ) {
338
- this.emitter.emit(selector.rawSelector, node);
171
+ this.emitter.emit(selector.source, node);
339
172
  }
340
173
  }
341
174
 
@@ -348,6 +181,11 @@ class NodeEventGenerator {
348
181
  applySelectors(node, isExit) {
349
182
  const nodeTypeKey = this.esqueryOptions?.nodeTypeKey || "type";
350
183
 
184
+ /*
185
+ * Get the selectors that may match this node. First, check
186
+ * to see if the node type has specific selectors,
187
+ * then gather the "any type" selectors.
188
+ */
351
189
  const selectorsByNodeType =
352
190
  (isExit
353
191
  ? this.exitSelectorsByNodeType
@@ -361,19 +199,23 @@ class NodeEventGenerator {
361
199
  * selectorsByNodeType and anyTypeSelectors were already sorted by specificity in the constructor.
362
200
  * Iterate through each of them, applying selectors in the right order.
363
201
  */
364
- let selectorsByTypeIndex = 0;
202
+ let selectorsByNodeTypeIndex = 0;
365
203
  let anyTypeSelectorsIndex = 0;
366
204
 
367
205
  while (
368
- selectorsByTypeIndex < selectorsByNodeType.length ||
206
+ selectorsByNodeTypeIndex < selectorsByNodeType.length ||
369
207
  anyTypeSelectorsIndex < anyTypeSelectors.length
370
208
  ) {
209
+ /*
210
+ * If we've already exhausted the selectors for this node type,
211
+ * or if the next any type selector is more specific than the
212
+ * next selector for this node type, apply the any type selector.
213
+ */
371
214
  if (
372
- selectorsByTypeIndex >= selectorsByNodeType.length ||
215
+ selectorsByNodeTypeIndex >= selectorsByNodeType.length ||
373
216
  (anyTypeSelectorsIndex < anyTypeSelectors.length &&
374
- compareSpecificity(
375
- anyTypeSelectors[anyTypeSelectorsIndex],
376
- selectorsByNodeType[selectorsByTypeIndex],
217
+ anyTypeSelectors[anyTypeSelectorsIndex].compare(
218
+ selectorsByNodeType[selectorsByNodeTypeIndex],
377
219
  ) < 0)
378
220
  ) {
379
221
  this.applySelector(
@@ -381,9 +223,10 @@ class NodeEventGenerator {
381
223
  anyTypeSelectors[anyTypeSelectorsIndex++],
382
224
  );
383
225
  } else {
226
+ // otherwise apply the node type selector
384
227
  this.applySelector(
385
228
  node,
386
- selectorsByNodeType[selectorsByTypeIndex++],
229
+ selectorsByNodeType[selectorsByNodeTypeIndex++],
387
230
  );
388
231
  }
389
232
  }
@@ -17,7 +17,8 @@ const { interpolate } = require("./interpolate");
17
17
  // Typedefs
18
18
  //------------------------------------------------------------------------------
19
19
 
20
- /** @typedef {import("../shared/types").LintMessage} LintMessage */
20
+ /** @typedef {import("../types").Linter.LintMessage} LintMessage */
21
+ /** @typedef {import("../types").Linter.LintSuggestion} SuggestionResult */
21
22
 
22
23
  /**
23
24
  * An error message description
package/lib/options.js CHANGED
@@ -213,6 +213,16 @@ module.exports = function (usingFlatConfig) {
213
213
  };
214
214
  }
215
215
 
216
+ let mcpFlag;
217
+
218
+ if (usingFlatConfig) {
219
+ mcpFlag = {
220
+ option: "mcp",
221
+ type: "Boolean",
222
+ description: "Start the ESLint MCP server",
223
+ };
224
+ }
225
+
216
226
  return optionator({
217
227
  prepend: "eslint [options] file.js [file.js] [dir]",
218
228
  defaults: {
@@ -499,6 +509,7 @@ module.exports = function (usingFlatConfig) {
499
509
  },
500
510
  statsFlag,
501
511
  flagFlag,
512
+ mcpFlag,
502
513
  ].filter(value => !!value),
503
514
  });
504
515
  };
@@ -15,7 +15,7 @@ const assert = require("node:assert"),
15
15
  path = require("node:path"),
16
16
  equal = require("fast-deep-equal"),
17
17
  Traverser = require("../shared/traverser"),
18
- { getRuleOptionsSchema } = require("../config/flat-config-helpers"),
18
+ { Config } = require("../config/config"),
19
19
  { Linter, SourceCodeFixer } = require("../linter"),
20
20
  { interpolate, getPlaceholderMatcher } = require("../linter/interpolate"),
21
21
  stringify = require("json-stable-stringify-without-jsonify");
@@ -39,9 +39,9 @@ const { SourceCode } = require("../languages/js/source-code");
39
39
  // Typedefs
40
40
  //------------------------------------------------------------------------------
41
41
 
42
- /** @typedef {import("../shared/types").Parser} Parser */
43
- /** @typedef {import("../shared/types").LanguageOptions} LanguageOptions */
44
- /** @typedef {import("../types").Rule.RuleModule} Rule */
42
+ /** @import { LanguageOptions, RuleDefinition } from "@eslint/core" */
43
+
44
+ /** @typedef {import("../types").Linter.Parser} Parser */
45
45
 
46
46
  /**
47
47
  * A test case that is expected to pass lint.
@@ -192,16 +192,24 @@ function cloneDeeplyExcludesParent(x) {
192
192
  /**
193
193
  * Freezes a given value deeply.
194
194
  * @param {any} x A value to freeze.
195
+ * @param {Set<Object>} seenObjects Objects already seen during the traversal.
195
196
  * @returns {void}
196
197
  */
197
- function freezeDeeply(x) {
198
+ function freezeDeeply(x, seenObjects = new Set()) {
198
199
  if (typeof x === "object" && x !== null) {
200
+ if (seenObjects.has(x)) {
201
+ return; // skip to avoid infinite recursion
202
+ }
203
+ seenObjects.add(x);
204
+
199
205
  if (Array.isArray(x)) {
200
- x.forEach(freezeDeeply);
206
+ x.forEach(element => {
207
+ freezeDeeply(element, seenObjects);
208
+ });
201
209
  } else {
202
210
  for (const key in x) {
203
211
  if (key !== "parent" && hasOwnProperty(x, key)) {
204
- freezeDeeply(x[key]);
212
+ freezeDeeply(x[key], seenObjects);
205
213
  }
206
214
  }
207
215
  }
@@ -545,7 +553,7 @@ class RuleTester {
545
553
  /**
546
554
  * Adds a new rule test to execute.
547
555
  * @param {string} ruleName The name of the rule to run.
548
- * @param {Rule} rule The rule to test.
556
+ * @param {RuleDefinition} rule The rule to test.
549
557
  * @param {{
550
558
  * valid: (ValidTestCase | string)[],
551
559
  * invalid: InvalidTestCase[]
@@ -759,7 +767,7 @@ class RuleTester {
759
767
  let schema;
760
768
 
761
769
  try {
762
- schema = getRuleOptionsSchema(rule);
770
+ schema = Config.getRuleOptionsSchema(rule);
763
771
  } catch (err) {
764
772
  err.message += metaSchemaDescription;
765
773
  throw err;
@@ -19,6 +19,7 @@ const astUtils = require("./utils/ast-utils");
19
19
  module.exports = {
20
20
  meta: {
21
21
  type: "suggestion",
22
+ hasSuggestions: true,
22
23
 
23
24
  docs: {
24
25
  description: "Require the use of `===` and `!==`",
@@ -63,6 +64,8 @@ module.exports = {
63
64
  messages: {
64
65
  unexpected:
65
66
  "Expected '{{expectedOperator}}' and instead saw '{{actualOperator}}'.",
67
+ replaceOperator:
68
+ "Use '{{expectedOperator}}' instead of '{{actualOperator}}'.",
66
69
  },
67
70
  },
68
71
 
@@ -138,22 +141,42 @@ module.exports = {
138
141
  token => token.value === node.operator,
139
142
  );
140
143
 
141
- context.report({
144
+ const commonReportParams = {
142
145
  node,
143
146
  loc: operatorToken.loc,
144
147
  messageId: "unexpected",
145
148
  data: { expectedOperator, actualOperator: node.operator },
146
- fix(fixer) {
147
- // If the comparison is a `typeof` comparison or both sides are literals with the same type, then it's safe to fix.
148
- if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) {
149
+ };
150
+
151
+ if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) {
152
+ context.report({
153
+ ...commonReportParams,
154
+ fix(fixer) {
149
155
  return fixer.replaceText(
150
156
  operatorToken,
151
157
  expectedOperator,
152
158
  );
153
- }
154
- return null;
155
- },
156
- });
159
+ },
160
+ });
161
+ } else {
162
+ context.report({
163
+ ...commonReportParams,
164
+ suggest: [
165
+ {
166
+ messageId: "replaceOperator",
167
+ data: {
168
+ expectedOperator,
169
+ actualOperator: node.operator,
170
+ },
171
+ fix: fixer =>
172
+ fixer.replaceText(
173
+ operatorToken,
174
+ expectedOperator,
175
+ ),
176
+ },
177
+ ],
178
+ });
179
+ }
157
180
  }
158
181
 
159
182
  return {
@@ -10,7 +10,7 @@
10
10
 
11
11
  const { LazyLoadingRuleMap } = require("./utils/lazy-loading-rule-map");
12
12
 
13
- /** @type {Map<string, import("../shared/types").Rule>} */
13
+ /** @type {Map<string, import("../types").Rule.RuleModule>} */
14
14
  module.exports = new LazyLoadingRuleMap(
15
15
  Object.entries({
16
16
  "accessor-pairs": () => require("./accessor-pairs"),
@@ -225,6 +225,7 @@ module.exports = new LazyLoadingRuleMap(
225
225
  "no-this-before-super": () => require("./no-this-before-super"),
226
226
  "no-throw-literal": () => require("./no-throw-literal"),
227
227
  "no-trailing-spaces": () => require("./no-trailing-spaces"),
228
+ "no-unassigned-vars": () => require("./no-unassigned-vars"),
228
229
  "no-undef": () => require("./no-undef"),
229
230
  "no-undef-init": () => require("./no-undef-init"),
230
231
  "no-undefined": () => require("./no-undefined"),