eslint 10.0.0-alpha.0 → 10.0.0-beta.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 (36) hide show
  1. package/README.md +1 -1
  2. package/lib/api.js +2 -2
  3. package/lib/cli-engine/formatters/stylish.js +65 -34
  4. package/lib/cli.js +18 -8
  5. package/lib/eslint/eslint.js +4 -2
  6. package/lib/languages/js/index.js +1 -0
  7. package/lib/languages/js/source-code/source-code.js +27 -165
  8. package/lib/languages/js/source-code/token-store/index.js +0 -26
  9. package/lib/linter/linter.js +1 -0
  10. package/lib/rule-tester/rule-tester.js +117 -43
  11. package/lib/rules/array-bracket-spacing.js +4 -4
  12. package/lib/rules/block-spacing.js +1 -1
  13. package/lib/rules/comma-spacing.js +2 -5
  14. package/lib/rules/computed-property-spacing.js +4 -4
  15. package/lib/rules/keyword-spacing.js +4 -4
  16. package/lib/rules/no-extra-parens.js +1 -1
  17. package/lib/rules/no-restricted-imports.js +56 -14
  18. package/lib/rules/no-spaced-func.js +1 -1
  19. package/lib/rules/no-useless-assignment.js +8 -5
  20. package/lib/rules/no-useless-constructor.js +13 -3
  21. package/lib/rules/no-whitespace-before-property.js +1 -1
  22. package/lib/rules/object-curly-spacing.js +2 -8
  23. package/lib/rules/require-yield.js +11 -1
  24. package/lib/rules/rest-spread-spacing.js +1 -4
  25. package/lib/rules/semi-spacing.js +2 -2
  26. package/lib/rules/space-before-blocks.js +1 -1
  27. package/lib/rules/space-before-function-paren.js +1 -4
  28. package/lib/rules/space-in-parens.js +4 -4
  29. package/lib/rules/space-infix-ops.js +4 -7
  30. package/lib/rules/switch-colon-spacing.js +1 -1
  31. package/lib/rules/template-tag-spacing.js +1 -1
  32. package/lib/rules/utils/ast-utils.js +117 -22
  33. package/lib/rules/yield-star-spacing.js +1 -2
  34. package/lib/types/index.d.ts +59 -36
  35. package/lib/types/use-at-your-own-risk.d.ts +1 -1
  36. package/package.json +5 -6
@@ -387,9 +387,10 @@ function normalizeTestCase(item) {
387
387
  * Asserts that the `errors` property of an invalid test case is valid.
388
388
  * @param {number | string[]} errors The `errors` property of the invalid test case.
389
389
  * @param {string} ruleName The name of the rule being tested.
390
+ * @param {Object} [assertionOptions] The assertion options for the test case.
390
391
  * @returns {void}
391
392
  */
392
- function assertErrorsProperty(errors, ruleName) {
393
+ function assertErrorsProperty(errors, ruleName, assertionOptions = {}) {
393
394
  const isNumber = typeof errors === "number";
394
395
  const isArray = Array.isArray(errors);
395
396
 
@@ -407,12 +408,75 @@ function assertErrorsProperty(errors, ruleName) {
407
408
  }
408
409
  }
409
410
 
411
+ const { requireMessage = false, requireLocation = false } =
412
+ assertionOptions;
413
+
410
414
  if (isArray) {
411
415
  assert.ok(
412
416
  errors.length !== 0,
413
417
  "Invalid cases must have at least one error",
414
418
  );
419
+
420
+ for (const [number, error] of errors.entries()) {
421
+ if (typeof error === "string" || error instanceof RegExp) {
422
+ // Just an error message.
423
+ assert.ok(
424
+ requireMessage !== "messageId" && !requireLocation,
425
+ `errors[${number}] should be an object when 'assertionOptions.requireMessage' is 'messageId' or 'assertionOptions.requireLocation' is true.`,
426
+ );
427
+ } else if (typeof error === "object" && error !== null) {
428
+ /*
429
+ * Error object.
430
+ * This may have a message, messageId, data, line, and/or column.
431
+ */
432
+
433
+ for (const propertyName of Object.keys(error)) {
434
+ assert.ok(
435
+ errorObjectParameters.has(propertyName),
436
+ `Invalid error property name '${propertyName}'. Expected one of ${friendlyErrorObjectParameterList}.`,
437
+ );
438
+ }
439
+
440
+ if (requireMessage === "message") {
441
+ assert.ok(
442
+ !hasOwnProperty(error, "messageId") &&
443
+ hasOwnProperty(error, "message"),
444
+ `errors[${number}] should specify 'message' (and not 'messageId') when 'assertionOptions.requireMessage' is 'message'.`,
445
+ );
446
+ } else if (requireMessage === "messageId") {
447
+ assert.ok(
448
+ !hasOwnProperty(error, "message") &&
449
+ hasOwnProperty(error, "messageId"),
450
+ `errors[${number}] should specify 'messageId' (and not 'message') when 'assertionOptions.requireMessage' is 'messageId'.`,
451
+ );
452
+ }
453
+
454
+ if (hasOwnProperty(error, "message")) {
455
+ assert.ok(
456
+ !hasOwnProperty(error, "messageId"),
457
+ `errors[${number}] should not specify both 'message' and 'messageId'.`,
458
+ );
459
+ assert.ok(
460
+ !hasOwnProperty(error, "data"),
461
+ `errors[${number}] should not specify both 'data' and 'message'.`,
462
+ );
463
+ } else {
464
+ assert.ok(
465
+ hasOwnProperty(error, "messageId"),
466
+ `errors[${number}] must specify either 'messageId' or 'message'.`,
467
+ );
468
+ }
469
+ } else {
470
+ assert.fail(
471
+ `errors[${number}] must be a string, RegExp, or an object.`,
472
+ );
473
+ }
474
+ }
415
475
  } else {
476
+ assert.ok(
477
+ !requireMessage && !requireLocation,
478
+ "Invalid cases must have 'errors' value as an array",
479
+ );
416
480
  assert.ok(
417
481
  errors > 0,
418
482
  "Invalid cases must have 'error' value greater than 0",
@@ -543,6 +607,16 @@ function assertTestCommonProperties(item) {
543
607
  * @throws {AssertionError} If the test case is not valid.
544
608
  */
545
609
  function assertValidTestCase(item, seenTestCases) {
610
+ // must not have properties of invalid test cases
611
+ assert.ok(
612
+ item.errors === void 0,
613
+ "Valid test case must not have 'errors' property",
614
+ );
615
+ assert.ok(
616
+ item.output === void 0,
617
+ "Valid test case must not have 'output' property",
618
+ );
619
+
546
620
  assertTestCommonProperties(item);
547
621
  checkDuplicateTestCase(item, seenTestCases);
548
622
  }
@@ -554,13 +628,19 @@ function assertValidTestCase(item, seenTestCases) {
554
628
  * @param {Object} item The invalid test case object to check.
555
629
  * @param {Set<string>} seenTestCases Set of serialized test cases to check for duplicates.
556
630
  * @param {string} ruleName The name of the rule being tested.
631
+ * @param {Object} [assertionOptions] The assertion options for the test case.
557
632
  * @returns {void}
558
633
  * @throws {AssertionError} If the test case is not valid.
559
634
  */
560
- function assertInvalidTestCase(item, seenTestCases, ruleName) {
635
+ function assertInvalidTestCase(
636
+ item,
637
+ seenTestCases,
638
+ ruleName,
639
+ assertionOptions = {},
640
+ ) {
561
641
  assertTestCommonProperties(item);
562
642
 
563
- assertErrorsProperty(item.errors, ruleName);
643
+ assertErrorsProperty(item.errors, ruleName, assertionOptions);
564
644
 
565
645
  // 'output' is optional, but if it exists it must be a string or null
566
646
  if (hasOwnProperty(item, "output")) {
@@ -753,6 +833,10 @@ class RuleTester {
753
833
  * @param {string} ruleName The name of the rule to run.
754
834
  * @param {RuleDefinition} rule The rule to test.
755
835
  * @param {{
836
+ * assertionOptions?: {
837
+ * requireMessage?: boolean | "message" | "messageId",
838
+ * requireLocation?: boolean
839
+ * },
756
840
  * valid: (ValidTestCase | string)[],
757
841
  * invalid: InvalidTestCase[]
758
842
  * }} test The collection of tests to run.
@@ -1133,6 +1217,9 @@ class RuleTester {
1133
1217
  * @private
1134
1218
  */
1135
1219
  function testInvalidTemplate(item) {
1220
+ const { requireMessage = false, requireLocation = false } =
1221
+ test.assertionOptions ?? {};
1222
+
1136
1223
  const ruleHasMetaMessages =
1137
1224
  hasOwnProperty(rule, "meta") &&
1138
1225
  hasOwnProperty(rule.meta, "messages");
@@ -1142,6 +1229,11 @@ class RuleTester {
1142
1229
  .join(", ")}]`
1143
1230
  : null;
1144
1231
 
1232
+ assert.ok(
1233
+ ruleHasMetaMessages || requireMessage !== "messageId",
1234
+ `Assertion options can not use 'requireMessage: "messageId"' if rule under test doesn't define 'meta.messages'.`,
1235
+ );
1236
+
1145
1237
  const result = runRuleForItem(item);
1146
1238
  const messages = result.messages;
1147
1239
 
@@ -1215,22 +1307,7 @@ class RuleTester {
1215
1307
  * This may have a message, messageId, data, line, and/or column.
1216
1308
  */
1217
1309
 
1218
- Object.keys(error).forEach(propertyName => {
1219
- assert.ok(
1220
- errorObjectParameters.has(propertyName),
1221
- `Invalid error property name '${propertyName}'. Expected one of ${friendlyErrorObjectParameterList}.`,
1222
- );
1223
- });
1224
-
1225
1310
  if (hasOwnProperty(error, "message")) {
1226
- assert.ok(
1227
- !hasOwnProperty(error, "messageId"),
1228
- "Error should not specify both 'message' and a 'messageId'.",
1229
- );
1230
- assert.ok(
1231
- !hasOwnProperty(error, "data"),
1232
- "Error should not specify both 'data' and 'message'.",
1233
- );
1234
1311
  assertMessageMatches(
1235
1312
  message.message,
1236
1313
  error.message,
@@ -1288,33 +1365,34 @@ class RuleTester {
1288
1365
  `Hydrated message "${rehydratedMessage}" does not match "${message.message}"`,
1289
1366
  );
1290
1367
  }
1291
- } else {
1292
- assert.fail(
1293
- "Test error must specify either a 'messageId' or 'message'.",
1294
- );
1295
1368
  }
1296
1369
 
1370
+ const locationProperties = [
1371
+ "line",
1372
+ "column",
1373
+ "endLine",
1374
+ "endColumn",
1375
+ ];
1297
1376
  const actualLocation = {};
1298
1377
  const expectedLocation = {};
1299
1378
 
1300
- if (hasOwnProperty(error, "line")) {
1301
- actualLocation.line = message.line;
1302
- expectedLocation.line = error.line;
1303
- }
1304
-
1305
- if (hasOwnProperty(error, "column")) {
1306
- actualLocation.column = message.column;
1307
- expectedLocation.column = error.column;
1308
- }
1309
-
1310
- if (hasOwnProperty(error, "endLine")) {
1311
- actualLocation.endLine = message.endLine;
1312
- expectedLocation.endLine = error.endLine;
1379
+ for (const key of locationProperties) {
1380
+ if (hasOwnProperty(error, key)) {
1381
+ actualLocation[key] = message[key];
1382
+ expectedLocation[key] = error[key];
1383
+ }
1313
1384
  }
1314
1385
 
1315
- if (hasOwnProperty(error, "endColumn")) {
1316
- actualLocation.endColumn = message.endColumn;
1317
- expectedLocation.endColumn = error.endColumn;
1386
+ if (requireLocation) {
1387
+ const missingKeys = locationProperties.filter(
1388
+ key =>
1389
+ !hasOwnProperty(error, key) &&
1390
+ hasOwnProperty(message, key),
1391
+ );
1392
+ assert.ok(
1393
+ missingKeys.length === 0,
1394
+ `Error is missing expected location properties: ${missingKeys.join(", ")}`,
1395
+ );
1318
1396
  }
1319
1397
 
1320
1398
  if (Object.keys(expectedLocation).length > 0) {
@@ -1540,11 +1618,6 @@ class RuleTester {
1540
1618
  }
1541
1619
  }
1542
1620
  }
1543
- } else {
1544
- // Message was an unexpected type
1545
- assert.fail(
1546
- `Error should be a string, object, or RegExp, but found (${util.inspect(message)})`,
1547
- );
1548
1621
  }
1549
1622
  }
1550
1623
  }
@@ -1621,6 +1694,7 @@ class RuleTester {
1621
1694
  item,
1622
1695
  seenTestCases,
1623
1696
  ruleName,
1697
+ test.assertionOptions,
1624
1698
  );
1625
1699
  testInvalidTemplate(item);
1626
1700
  } finally {
@@ -258,13 +258,13 @@ module.exports = {
258
258
  if (astUtils.isTokenOnSameLine(first, second)) {
259
259
  if (
260
260
  openingBracketMustBeSpaced &&
261
- !sourceCode.isSpaceBetweenTokens(first, second)
261
+ !sourceCode.isSpaceBetween(first, second)
262
262
  ) {
263
263
  reportRequiredBeginningSpace(node, first);
264
264
  }
265
265
  if (
266
266
  !openingBracketMustBeSpaced &&
267
- sourceCode.isSpaceBetweenTokens(first, second)
267
+ sourceCode.isSpaceBetween(first, second)
268
268
  ) {
269
269
  reportNoBeginningSpace(node, first);
270
270
  }
@@ -276,13 +276,13 @@ module.exports = {
276
276
  ) {
277
277
  if (
278
278
  closingBracketMustBeSpaced &&
279
- !sourceCode.isSpaceBetweenTokens(penultimate, last)
279
+ !sourceCode.isSpaceBetween(penultimate, last)
280
280
  ) {
281
281
  reportRequiredEndingSpace(node, last);
282
282
  }
283
283
  if (
284
284
  !closingBracketMustBeSpaced &&
285
- sourceCode.isSpaceBetweenTokens(penultimate, last)
285
+ sourceCode.isSpaceBetween(penultimate, last)
286
286
  ) {
287
287
  reportNoEndingSpace(node, last);
288
288
  }
@@ -95,7 +95,7 @@ module.exports = {
95
95
  function isValid(left, right) {
96
96
  return (
97
97
  !util.isTokenOnSameLine(left, right) ||
98
- sourceCode.isSpaceBetweenTokens(left, right) === always
98
+ sourceCode.isSpaceBetween(left, right) === always
99
99
  );
100
100
  }
101
101
 
@@ -178,10 +178,7 @@ module.exports = {
178
178
  !commaTokensToIgnore.includes(token) &&
179
179
  astUtils.isTokenOnSameLine(previousToken, token) &&
180
180
  options.before !==
181
- sourceCode.isSpaceBetweenTokens(
182
- previousToken,
183
- token,
184
- )
181
+ sourceCode.isSpaceBetween(previousToken, token)
185
182
  ) {
186
183
  report(token, "before", previousToken);
187
184
  }
@@ -195,7 +192,7 @@ module.exports = {
195
192
  !(!options.after && nextToken.type === "Line") && // special case, allow space before line comment
196
193
  astUtils.isTokenOnSameLine(token, nextToken) &&
197
194
  options.after !==
198
- sourceCode.isSpaceBetweenTokens(token, nextToken)
195
+ sourceCode.isSpaceBetween(token, nextToken)
199
196
  ) {
200
197
  report(token, "after", nextToken);
201
198
  }
@@ -203,13 +203,13 @@ module.exports = {
203
203
  if (astUtils.isTokenOnSameLine(before, first)) {
204
204
  if (propertyNameMustBeSpaced) {
205
205
  if (
206
- !sourceCode.isSpaceBetweenTokens(before, first) &&
206
+ !sourceCode.isSpaceBetween(before, first) &&
207
207
  astUtils.isTokenOnSameLine(before, first)
208
208
  ) {
209
209
  reportRequiredBeginningSpace(node, before);
210
210
  }
211
211
  } else {
212
- if (sourceCode.isSpaceBetweenTokens(before, first)) {
212
+ if (sourceCode.isSpaceBetween(before, first)) {
213
213
  reportNoBeginningSpace(node, before, first);
214
214
  }
215
215
  }
@@ -218,13 +218,13 @@ module.exports = {
218
218
  if (astUtils.isTokenOnSameLine(last, after)) {
219
219
  if (propertyNameMustBeSpaced) {
220
220
  if (
221
- !sourceCode.isSpaceBetweenTokens(last, after) &&
221
+ !sourceCode.isSpaceBetween(last, after) &&
222
222
  astUtils.isTokenOnSameLine(last, after)
223
223
  ) {
224
224
  reportRequiredEndingSpace(node, after);
225
225
  }
226
226
  } else {
227
- if (sourceCode.isSpaceBetweenTokens(last, after)) {
227
+ if (sourceCode.isSpaceBetween(last, after)) {
228
228
  reportNoEndingSpace(node, after, last);
229
229
  }
230
230
  }
@@ -163,7 +163,7 @@ module.exports = {
163
163
  !isOpenParenOfTemplate(prevToken) &&
164
164
  !tokensToIgnore.has(prevToken) &&
165
165
  astUtils.isTokenOnSameLine(prevToken, token) &&
166
- !sourceCode.isSpaceBetweenTokens(prevToken, token)
166
+ !sourceCode.isSpaceBetween(prevToken, token)
167
167
  ) {
168
168
  context.report({
169
169
  loc: token.loc,
@@ -192,7 +192,7 @@ module.exports = {
192
192
  !isOpenParenOfTemplate(prevToken) &&
193
193
  !tokensToIgnore.has(prevToken) &&
194
194
  astUtils.isTokenOnSameLine(prevToken, token) &&
195
- sourceCode.isSpaceBetweenTokens(prevToken, token)
195
+ sourceCode.isSpaceBetween(prevToken, token)
196
196
  ) {
197
197
  context.report({
198
198
  loc: { start: prevToken.loc.end, end: token.loc.start },
@@ -224,7 +224,7 @@ module.exports = {
224
224
  !isCloseParenOfTemplate(nextToken) &&
225
225
  !tokensToIgnore.has(nextToken) &&
226
226
  astUtils.isTokenOnSameLine(token, nextToken) &&
227
- !sourceCode.isSpaceBetweenTokens(token, nextToken)
227
+ !sourceCode.isSpaceBetween(token, nextToken)
228
228
  ) {
229
229
  context.report({
230
230
  loc: token.loc,
@@ -253,7 +253,7 @@ module.exports = {
253
253
  !isCloseParenOfTemplate(nextToken) &&
254
254
  !tokensToIgnore.has(nextToken) &&
255
255
  astUtils.isTokenOnSameLine(token, nextToken) &&
256
- sourceCode.isSpaceBetweenTokens(token, nextToken)
256
+ sourceCode.isSpaceBetween(token, nextToken)
257
257
  ) {
258
258
  context.report({
259
259
  loc: { start: token.loc.end, end: nextToken.loc.start },
@@ -470,7 +470,7 @@ module.exports = {
470
470
  return (
471
471
  rightParenToken &&
472
472
  tokenAfterRightParen &&
473
- !sourceCode.isSpaceBetweenTokens(
473
+ !sourceCode.isSpaceBetween(
474
474
  rightParenToken,
475
475
  tokenAfterRightParen,
476
476
  ) &&
@@ -10,6 +10,30 @@
10
10
 
11
11
  const astUtils = require("./utils/ast-utils");
12
12
 
13
+ //------------------------------------------------------------------------------
14
+ // Helpers
15
+ //------------------------------------------------------------------------------
16
+
17
+ /**
18
+ * Format import names for error messages.
19
+ * @param {string[]} importNames The import names to format.
20
+ * @returns {string} The formatted import names.
21
+ */
22
+ function formatImportNames(importNames) {
23
+ return new Intl.ListFormat("en-US").format(
24
+ importNames.map(name => `'${name}'`),
25
+ );
26
+ }
27
+
28
+ /**
29
+ * Returns "is" or "are" based on the number of import names.
30
+ * @param {string[]} importNames The import names to check.
31
+ * @returns {string} "is" if one import name, otherwise "are".
32
+ */
33
+ function isOrAre(importNames) {
34
+ return importNames.length === 1 ? "is" : "are";
35
+ }
36
+
13
37
  //------------------------------------------------------------------------------
14
38
  // Rule Definition
15
39
  //------------------------------------------------------------------------------
@@ -175,22 +199,22 @@ module.exports = {
175
199
  "'{{importName}}' import from '{{importSource}}' is restricted from being used by a pattern. {{customMessage}}",
176
200
 
177
201
  patternAndEverything:
178
- "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted from being used by a pattern.",
202
+ "* import is invalid because {{importNames}} from '{{importSource}}' {{isOrAre}} restricted from being used by a pattern.",
179
203
 
180
204
  patternAndEverythingWithRegexImportName:
181
205
  "* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used.",
182
206
  patternAndEverythingWithCustomMessage:
183
207
  // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
184
- "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted from being used by a pattern. {{customMessage}}",
208
+ "* import is invalid because {{importNames}} from '{{importSource}}' {{isOrAre}} restricted from being used by a pattern. {{customMessage}}",
185
209
  patternAndEverythingWithRegexImportNameAndCustomMessage:
186
210
  // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
187
211
  "* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used. {{customMessage}}",
188
212
 
189
213
  everything:
190
- "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted.",
214
+ "* import is invalid because {{importNames}} from '{{importSource}}' {{isOrAre}} restricted.",
191
215
  everythingWithCustomMessage:
192
216
  // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
193
- "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted. {{customMessage}}",
217
+ "* import is invalid because {{importNames}} from '{{importSource}}' {{isOrAre}} restricted. {{customMessage}}",
194
218
 
195
219
  importName:
196
220
  "'{{importName}}' import from '{{importSource}}' is restricted.",
@@ -199,16 +223,16 @@ module.exports = {
199
223
  "'{{importName}}' import from '{{importSource}}' is restricted. {{customMessage}}",
200
224
 
201
225
  allowedImportName:
202
- "'{{importName}}' import from '{{importSource}}' is restricted because only '{{allowedImportNames}}' import(s) is/are allowed.",
226
+ "'{{importName}}' import from '{{importSource}}' is restricted because only {{allowedImportNames}} {{isOrAre}} allowed.",
203
227
  allowedImportNameWithCustomMessage:
204
228
  // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
205
- "'{{importName}}' import from '{{importSource}}' is restricted because only '{{allowedImportNames}}' import(s) is/are allowed. {{customMessage}}",
229
+ "'{{importName}}' import from '{{importSource}}' is restricted because only {{allowedImportNames}} {{isOrAre}} allowed. {{customMessage}}",
206
230
 
207
231
  everythingWithAllowImportNames:
208
- "* import is invalid because only '{{allowedImportNames}}' from '{{importSource}}' is/are allowed.",
232
+ "* import is invalid because only {{allowedImportNames}} from '{{importSource}}' {{isOrAre}} allowed.",
209
233
  everythingWithAllowImportNamesAndCustomMessage:
210
234
  // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
211
- "* import is invalid because only '{{allowedImportNames}}' from '{{importSource}}' is/are allowed. {{customMessage}}",
235
+ "* import is invalid because only {{allowedImportNames}} from '{{importSource}}' {{isOrAre}} allowed. {{customMessage}}",
212
236
 
213
237
  allowedImportNamePattern:
214
238
  "'{{importName}}' import from '{{importSource}}' is restricted because only imports that match the pattern '{{allowedImportNamePattern}}' are allowed from '{{importSource}}'.",
@@ -452,7 +476,10 @@ module.exports = {
452
476
  loc: specifier.loc,
453
477
  data: {
454
478
  importSource,
455
- importNames: restrictedImportNames,
479
+ importNames: formatImportNames(
480
+ restrictedImportNames,
481
+ ),
482
+ isOrAre: isOrAre(restrictedImportNames),
456
483
  customMessage,
457
484
  },
458
485
  });
@@ -465,7 +492,11 @@ module.exports = {
465
492
  loc: specifier.loc,
466
493
  data: {
467
494
  importSource,
468
- allowedImportNames,
495
+ allowedImportNames:
496
+ formatImportNames(
497
+ allowedImportNames,
498
+ ),
499
+ isOrAre: isOrAre(allowedImportNames),
469
500
  customMessage,
470
501
  },
471
502
  });
@@ -525,7 +556,11 @@ module.exports = {
525
556
  importSource,
526
557
  customMessage,
527
558
  importName,
528
- allowedImportNames,
559
+ allowedImportNames:
560
+ formatImportNames(
561
+ allowedImportNames,
562
+ ),
563
+ isOrAre: isOrAre(allowedImportNames),
529
564
  },
530
565
  });
531
566
  });
@@ -612,7 +647,10 @@ module.exports = {
612
647
  loc: specifier.loc,
613
648
  data: {
614
649
  importSource,
615
- importNames: restrictedImportNames,
650
+ importNames: formatImportNames(
651
+ restrictedImportNames,
652
+ ),
653
+ isOrAre: isOrAre(restrictedImportNames),
616
654
  customMessage,
617
655
  },
618
656
  });
@@ -625,7 +663,9 @@ module.exports = {
625
663
  loc: specifier.loc,
626
664
  data: {
627
665
  importSource,
628
- allowedImportNames,
666
+ allowedImportNames:
667
+ formatImportNames(allowedImportNames),
668
+ isOrAre: isOrAre(allowedImportNames),
629
669
  customMessage,
630
670
  },
631
671
  });
@@ -713,7 +753,9 @@ module.exports = {
713
753
  importSource,
714
754
  customMessage,
715
755
  importName,
716
- allowedImportNames,
756
+ allowedImportNames:
757
+ formatImportNames(allowedImportNames),
758
+ isOrAre: isOrAre(allowedImportNames),
717
759
  },
718
760
  });
719
761
  });
@@ -81,7 +81,7 @@ module.exports = {
81
81
  if (
82
82
  parenToken &&
83
83
  parenToken.range[1] < node.range[1] &&
84
- sourceCode.isSpaceBetweenTokens(prevToken, parenToken)
84
+ sourceCode.isSpaceBetween(prevToken, parenToken)
85
85
  ) {
86
86
  context.report({
87
87
  node,
@@ -336,9 +336,12 @@ module.exports = {
336
336
  }
337
337
 
338
338
  if (
339
- targetAssignment.variable.references.some(
340
- ref => ref.identifier.type !== "Identifier",
341
- )
339
+ targetAssignment.variable.references.some(ref => {
340
+ const type = ref.identifier.type;
341
+ return (
342
+ type !== "Identifier" && type !== "JSXIdentifier"
343
+ );
344
+ })
342
345
  ) {
343
346
  /**
344
347
  * Skip checking for a variable that has at least one non-identifier reference.
@@ -529,7 +532,7 @@ module.exports = {
529
532
  TryStatement(node) {
530
533
  scopeStack.tryStatementBlocks.push(node.block);
531
534
  },
532
- Identifier(node) {
535
+ "Identifier, JSXIdentifier"(node) {
533
536
  for (const segment of scopeStack.currentSegments) {
534
537
  const segmentInfo = scopeStack.segments[segment.id];
535
538
 
@@ -539,7 +542,7 @@ module.exports = {
539
542
  segmentInfo.last = node;
540
543
  }
541
544
  },
542
- ":matches(VariableDeclarator[init!=null], AssignmentExpression, UpdateExpression):exit"(
545
+ "VariableDeclarator[init!=null], AssignmentExpression, UpdateExpression:exit"(
543
546
  node,
544
547
  ) {
545
548
  if (scopeStack.currentSegments.size === 0) {
@@ -185,6 +185,8 @@ module.exports = {
185
185
  },
186
186
 
187
187
  create(context) {
188
+ const { sourceCode } = context;
189
+
188
190
  /**
189
191
  * Checks whether a node is a redundant constructor
190
192
  * @param {ASTNode} node node to check
@@ -211,6 +213,14 @@ module.exports = {
211
213
  const body = node.value.body.body;
212
214
  const ctorParams = node.value.params;
213
215
  const superClass = node.parent.parent.superClass;
216
+ const parenToken = sourceCode.getFirstToken(
217
+ node,
218
+ astUtils.isOpeningParenToken,
219
+ );
220
+ const loc = {
221
+ start: node.loc.start,
222
+ end: sourceCode.getTokenBefore(parenToken).loc.end,
223
+ };
214
224
 
215
225
  if (
216
226
  superClass
@@ -218,19 +228,19 @@ module.exports = {
218
228
  : body.length === 0
219
229
  ) {
220
230
  context.report({
221
- node,
231
+ loc,
222
232
  messageId: "noUselessConstructor",
223
233
  suggest: [
224
234
  {
225
235
  messageId: "removeConstructor",
226
236
  *fix(fixer) {
227
237
  const nextToken =
228
- context.sourceCode.getTokenAfter(node);
238
+ sourceCode.getTokenAfter(node);
229
239
  const addSemiColon =
230
240
  nextToken.type === "Punctuator" &&
231
241
  nextToken.value === "[" &&
232
242
  astUtils.needsPrecedingSemicolon(
233
- context.sourceCode,
243
+ sourceCode,
234
244
  node,
235
245
  );
236
246
 
@@ -141,7 +141,7 @@ module.exports = {
141
141
  leftToken = sourceCode.getTokenBefore(rightToken, 1);
142
142
  }
143
143
 
144
- if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken)) {
144
+ if (sourceCode.isSpaceBetween(leftToken, rightToken)) {
145
145
  reportError(node, leftToken, rightToken);
146
146
  }
147
147
  },
@@ -204,10 +204,7 @@ module.exports = {
204
204
  */
205
205
  function validateBraceSpacing(node, first, second, penultimate, last) {
206
206
  if (astUtils.isTokenOnSameLine(first, second)) {
207
- const firstSpaced = sourceCode.isSpaceBetweenTokens(
208
- first,
209
- second,
210
- );
207
+ const firstSpaced = sourceCode.isSpaceBetween(first, second);
211
208
 
212
209
  if (options.spaced && !firstSpaced) {
213
210
  reportRequiredBeginningSpace(node, first);
@@ -236,10 +233,7 @@ module.exports = {
236
233
  ? !options.spaced
237
234
  : options.spaced;
238
235
 
239
- const lastSpaced = sourceCode.isSpaceBetweenTokens(
240
- penultimate,
241
- last,
242
- );
236
+ const lastSpaced = sourceCode.isSpaceBetween(penultimate, last);
243
237
 
244
238
  if (closingCurlyBraceMustBeSpaced && !lastSpaced) {
245
239
  reportRequiredEndingSpace(node, last);