eslint 7.28.0 → 7.29.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/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ v7.29.0 - June 18, 2021
2
+
3
+ * [`bfbfe5c`](https://github.com/eslint/eslint/commit/bfbfe5c1fd4c39a06d5e159dbe48479ca4305fc0) New: Add only to RuleTester (refs eslint/rfcs#73) (#14677) (Brandon Mills)
4
+ * [`c2cd7b4`](https://github.com/eslint/eslint/commit/c2cd7b4a18057ca6067bdfc16de771dc5d90c0ea) New: Add ESLint#getRulesMetaForResults() (refs #13654) (#14716) (Nicholas C. Zakas)
5
+ * [`eea7e0d`](https://github.com/eslint/eslint/commit/eea7e0d09d6ef43d6663cbe424e7974764a5f7fe) Chore: remove duplicate code (#14719) (Nitin Kumar)
6
+ * [`6a1c7a0`](https://github.com/eslint/eslint/commit/6a1c7a0dac050ea5876972c50563a7eb867b38d3) Fix: allow fallthrough comment inside block (fixes #14701) (#14702) (Kevin Gibbons)
7
+ * [`a47e5e3`](https://github.com/eslint/eslint/commit/a47e5e30b0da364593b6881f6826c595da8696f5) Docs: Add Mega-Linter to the list of integrations (#14707) (Nicolas Vuillamy)
8
+ * [`353ddf9`](https://github.com/eslint/eslint/commit/353ddf965078030794419b089994373e27ffc86e) Chore: enable reportUnusedDisableDirectives in eslint-config-eslint (#14699) (薛定谔的猫)
9
+ * [`757c495`](https://github.com/eslint/eslint/commit/757c49584a5852c468c1b4a0b74ad3aa39d954e5) Chore: add some rules to eslint-config-eslint (#14692) (薛定谔的猫)
10
+ * [`c93a222`](https://github.com/eslint/eslint/commit/c93a222563177a9b5bc7a59aa106bc0a6d31e063) Docs: fix a broken link (#14697) (Sam Chen)
11
+ * [`655c118`](https://github.com/eslint/eslint/commit/655c1187fc845bac61ae8d06c556f1a59ee2071b) Sponsors: Sync README with website (ESLint Jenkins)
12
+ * [`e2bed2e`](https://github.com/eslint/eslint/commit/e2bed2ead22b575d55ccaeed94eecd3a979dd871) Sponsors: Sync README with website (ESLint Jenkins)
13
+ * [`8490fb4`](https://github.com/eslint/eslint/commit/8490fb42e559ef0b3c34ac60be4e05e0d879a9cb) Sponsors: Sync README with website (ESLint Jenkins)
14
+ * [`ddbe877`](https://github.com/eslint/eslint/commit/ddbe877c95224e127215d35562a175c6f2b7ba22) Sponsors: Sync README with website (ESLint Jenkins)
15
+
1
16
  v7.28.0 - June 4, 2021
2
17
 
3
18
  * [`1237705`](https://github.com/eslint/eslint/commit/1237705dd08c209c5e3136045ec51a4ba87a3abe) Upgrade: @eslint/eslintrc to 0.4.2 (#14672) (Milos Djermanovic)
package/README.md CHANGED
@@ -281,9 +281,9 @@ The following companies, organizations, and individuals support ESLint's ongoing
281
281
  <!--sponsorsstart-->
282
282
  <h3>Platinum Sponsors</h3>
283
283
  <p><a href="https://automattic.com"><img src="https://images.opencollective.com/photomatt/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
284
- <p><a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
284
+ <p><a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://coinbase.com"><img src="https://avatars.githubusercontent.com/u/1885080?v=4" alt="Coinbase" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
285
285
  <p><a href="https://retool.com/"><img src="https://images.opencollective.com/retool/98ea68e/logo.png" alt="Retool" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
286
- <p><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="null"><img src="https://images.opencollective.com/bugsnag-stability-monitoring/c2cef36/logo.png" alt="Bugsnag Stability Monitoring" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" 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/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a></p>
286
+ <p><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="null"><img src="https://images.opencollective.com/bugsnag-stability-monitoring/c2cef36/logo.png" alt="Bugsnag Stability Monitoring" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" 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/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://www.practiceignition.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Practice Ignition" height="32"></a></p>
287
287
  <!--sponsorsend-->
288
288
 
289
289
  ## <a name="technology-sponsors"></a>Technology Sponsors
@@ -514,6 +514,39 @@ class ESLint {
514
514
  return CLIEngine.getErrorResults(results);
515
515
  }
516
516
 
517
+ /**
518
+ * Returns meta objects for each rule represented in the lint results.
519
+ * @param {LintResult[]} results The results to fetch rules meta for.
520
+ * @returns {Object} A mapping of ruleIds to rule meta objects.
521
+ */
522
+ getRulesMetaForResults(results) {
523
+
524
+ const resultRuleIds = new Set();
525
+
526
+ // first gather all ruleIds from all results
527
+
528
+ for (const result of results) {
529
+ for (const { ruleId } of result.messages) {
530
+ resultRuleIds.add(ruleId);
531
+ }
532
+ }
533
+
534
+ // create a map of all rules in the results
535
+
536
+ const { cliEngine } = privateMembersMap.get(this);
537
+ const rules = cliEngine.getRules();
538
+ const resultRules = new Map();
539
+
540
+ for (const [ruleId, rule] of rules) {
541
+ if (resultRuleIds.has(ruleId)) {
542
+ resultRules.set(ruleId, rule);
543
+ }
544
+ }
545
+
546
+ return createRulesMeta(resultRules);
547
+
548
+ }
549
+
517
550
  /**
518
551
  * Executes the current configuration on an array of file and directory names.
519
552
  * @param {string[]} patterns An array of file and directory names.
@@ -552,9 +585,12 @@ class ESLint {
552
585
  ...unknownOptions
553
586
  } = options || {};
554
587
 
555
- for (const key of Object.keys(unknownOptions)) {
556
- throw new Error(`'options' must not include the unknown option '${key}'`);
588
+ const unknownOptionKeys = Object.keys(unknownOptions);
589
+
590
+ if (unknownOptionKeys.length > 0) {
591
+ throw new Error(`'options' must not include the unknown option(s): ${unknownOptionKeys.join(", ")}`);
557
592
  }
593
+
558
594
  if (filePath !== void 0 && !isNonEmptyString(filePath)) {
559
595
  throw new Error("'options.filePath' must be a non-empty string or undefined");
560
596
  }
@@ -50,8 +50,7 @@ function findPackageJson(startDir) {
50
50
  */
51
51
  function installSyncSaveDev(packages) {
52
52
  const packageList = Array.isArray(packages) ? packages : [packages];
53
- const npmProcess = spawn.sync("npm", ["i", "--save-dev"].concat(packageList),
54
- { stdio: "inherit" });
53
+ const npmProcess = spawn.sync("npm", ["i", "--save-dev"].concat(packageList), { stdio: "inherit" });
55
54
  const error = npmProcess.error;
56
55
 
57
56
  if (error && error.code === "ENOENT") {
@@ -71,6 +71,7 @@ const espreePath = require.resolve("espree");
71
71
  * @property {{ [name: string]: any }} [parserOptions] Options for the parser.
72
72
  * @property {{ [name: string]: "readonly" | "writable" | "off" }} [globals] The additional global variables.
73
73
  * @property {{ [name: string]: boolean }} [env] Environments for the test case.
74
+ * @property {boolean} [only] Run only this test case or the subset of test cases with this property.
74
75
  */
75
76
 
76
77
  /**
@@ -86,6 +87,7 @@ const espreePath = require.resolve("espree");
86
87
  * @property {{ [name: string]: any }} [parserOptions] Options for the parser.
87
88
  * @property {{ [name: string]: "readonly" | "writable" | "off" }} [globals] The additional global variables.
88
89
  * @property {{ [name: string]: boolean }} [env] Environments for the test case.
90
+ * @property {boolean} [only] Run only this test case or the subset of test cases with this property.
89
91
  */
90
92
 
91
93
  /**
@@ -121,7 +123,8 @@ const RuleTesterParameters = [
121
123
  "filename",
122
124
  "options",
123
125
  "errors",
124
- "output"
126
+ "output",
127
+ "only"
125
128
  ];
126
129
 
127
130
  /*
@@ -282,6 +285,7 @@ function wrapParser(parser) {
282
285
  // default separators for testing
283
286
  const DESCRIBE = Symbol("describe");
284
287
  const IT = Symbol("it");
288
+ const IT_ONLY = Symbol("itOnly");
285
289
 
286
290
  /**
287
291
  * This is `it` default handler if `it` don't exist.
@@ -400,6 +404,46 @@ class RuleTester {
400
404
  this[IT] = value;
401
405
  }
402
406
 
407
+ /**
408
+ * Adds the `only` property to a test to run it in isolation.
409
+ * @param {string | ValidTestCase | InvalidTestCase} item A single test to run by itself.
410
+ * @returns {ValidTestCase | InvalidTestCase} The test with `only` set.
411
+ */
412
+ static only(item) {
413
+ if (typeof item === "string") {
414
+ return { code: item, only: true };
415
+ }
416
+
417
+ return { ...item, only: true };
418
+ }
419
+
420
+ static get itOnly() {
421
+ if (typeof this[IT_ONLY] === "function") {
422
+ return this[IT_ONLY];
423
+ }
424
+ if (typeof this[IT] === "function" && typeof this[IT].only === "function") {
425
+ return Function.bind.call(this[IT].only, this[IT]);
426
+ }
427
+ if (typeof it === "function" && typeof it.only === "function") {
428
+ return Function.bind.call(it.only, it);
429
+ }
430
+
431
+ if (typeof this[DESCRIBE] === "function" || typeof this[IT] === "function") {
432
+ throw new Error(
433
+ "Set `RuleTester.itOnly` to use `only` with a custom test framework.\n" +
434
+ "See https://eslint.org/docs/developer-guide/nodejs-api#customizing-ruletester for more."
435
+ );
436
+ }
437
+ if (typeof it === "function") {
438
+ throw new Error("The current test framework does not support exclusive tests with `only`.");
439
+ }
440
+ throw new Error("To use `only`, use RuleTester with a test framework that provides `it.only()` like Mocha.");
441
+ }
442
+
443
+ static set itOnly(value) {
444
+ this[IT_ONLY] = value;
445
+ }
446
+
403
447
  /**
404
448
  * Define a rule for one particular run of tests.
405
449
  * @param {string} name The name of the rule to define.
@@ -610,7 +654,8 @@ class RuleTester {
610
654
  const messages = result.messages;
611
655
 
612
656
  assert.strictEqual(messages.length, 0, util.format("Should have no errors but had %d: %s",
613
- messages.length, util.inspect(messages)));
657
+ messages.length,
658
+ util.inspect(messages)));
614
659
 
615
660
  assertASTDidntChange(result.beforeAST, result.afterAST);
616
661
  }
@@ -665,13 +710,18 @@ class RuleTester {
665
710
  }
666
711
 
667
712
  assert.strictEqual(messages.length, item.errors, util.format("Should have %d error%s but had %d: %s",
668
- item.errors, item.errors === 1 ? "" : "s", messages.length, util.inspect(messages)));
713
+ item.errors,
714
+ item.errors === 1 ? "" : "s",
715
+ messages.length,
716
+ util.inspect(messages)));
669
717
  } else {
670
718
  assert.strictEqual(
671
- messages.length, item.errors.length,
672
- util.format(
719
+ messages.length, item.errors.length, util.format(
673
720
  "Should have %d error%s but had %d: %s",
674
- item.errors.length, item.errors.length === 1 ? "" : "s", messages.length, util.inspect(messages)
721
+ item.errors.length,
722
+ item.errors.length === 1 ? "" : "s",
723
+ messages.length,
724
+ util.inspect(messages)
675
725
  )
676
726
  );
677
727
 
@@ -885,23 +935,29 @@ class RuleTester {
885
935
  RuleTester.describe(ruleName, () => {
886
936
  RuleTester.describe("valid", () => {
887
937
  test.valid.forEach(valid => {
888
- RuleTester.it(sanitize(typeof valid === "object" ? valid.code : valid), () => {
889
- testValidTemplate(valid);
890
- });
938
+ RuleTester[valid.only ? "itOnly" : "it"](
939
+ sanitize(typeof valid === "object" ? valid.code : valid),
940
+ () => {
941
+ testValidTemplate(valid);
942
+ }
943
+ );
891
944
  });
892
945
  });
893
946
 
894
947
  RuleTester.describe("invalid", () => {
895
948
  test.invalid.forEach(invalid => {
896
- RuleTester.it(sanitize(invalid.code), () => {
897
- testInvalidTemplate(invalid);
898
- });
949
+ RuleTester[invalid.only ? "itOnly" : "it"](
950
+ sanitize(invalid.code),
951
+ () => {
952
+ testInvalidTemplate(invalid);
953
+ }
954
+ );
899
955
  });
900
956
  });
901
957
  });
902
958
  }
903
959
  }
904
960
 
905
- RuleTester[DESCRIBE] = RuleTester[IT] = null;
961
+ RuleTester[DESCRIBE] = RuleTester[IT] = RuleTester[IT_ONLY] = null;
906
962
 
907
963
  module.exports = RuleTester;
@@ -207,8 +207,7 @@ module.exports = {
207
207
  * they are always valid regardless of an undefined item.
208
208
  */
209
209
  if (astUtils.isCommaToken(commaToken)) {
210
- validateCommaItemSpacing(previousItemToken, commaToken,
211
- currentItemToken, reportItem);
210
+ validateCommaItemSpacing(previousItemToken, commaToken, currentItemToken, reportItem);
212
211
  }
213
212
 
214
213
  if (item) {
@@ -1177,8 +1177,7 @@ module.exports = {
1177
1177
  offsets.setDesiredOffset(questionMarkToken, firstToken, 1);
1178
1178
  offsets.setDesiredOffset(colonToken, firstToken, 1);
1179
1179
 
1180
- offsets.setDesiredOffset(firstConsequentToken, firstToken,
1181
- firstConsequentToken.type === "Punctuator" &&
1180
+ offsets.setDesiredOffset(firstConsequentToken, firstToken, firstConsequentToken.type === "Punctuator" &&
1182
1181
  options.offsetTernaryExpressions ? 2 : 1);
1183
1182
 
1184
1183
  /*
@@ -1204,8 +1203,7 @@ module.exports = {
1204
1203
  * If `baz` were aligned with `bar` rather than being offset by 1 from `foo`, `baz` would end up
1205
1204
  * having no expected indentation.
1206
1205
  */
1207
- offsets.setDesiredOffset(firstAlternateToken, firstToken,
1208
- firstAlternateToken.type === "Punctuator" &&
1206
+ offsets.setDesiredOffset(firstAlternateToken, firstToken, firstAlternateToken.type === "Punctuator" &&
1209
1207
  options.offsetTernaryExpressions ? 2 : 1);
1210
1208
  }
1211
1209
  }
@@ -11,15 +11,26 @@
11
11
  const DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/iu;
12
12
 
13
13
  /**
14
- * Checks whether or not a given node has a fallthrough comment.
15
- * @param {ASTNode} node A SwitchCase node to get comments.
14
+ * Checks whether or not a given case has a fallthrough comment.
15
+ * @param {ASTNode} caseWhichFallsThrough SwitchCase node which falls through.
16
+ * @param {ASTNode} subsequentCase The case after caseWhichFallsThrough.
16
17
  * @param {RuleContext} context A rule context which stores comments.
17
18
  * @param {RegExp} fallthroughCommentPattern A pattern to match comment to.
18
- * @returns {boolean} `true` if the node has a valid fallthrough comment.
19
+ * @returns {boolean} `true` if the case has a valid fallthrough comment.
19
20
  */
20
- function hasFallthroughComment(node, context, fallthroughCommentPattern) {
21
+ function hasFallthroughComment(caseWhichFallsThrough, subsequentCase, context, fallthroughCommentPattern) {
21
22
  const sourceCode = context.getSourceCode();
22
- const comment = sourceCode.getCommentsBefore(node).pop();
23
+
24
+ if (caseWhichFallsThrough.consequent.length === 1 && caseWhichFallsThrough.consequent[0].type === "BlockStatement") {
25
+ const trailingCloseBrace = sourceCode.getLastToken(caseWhichFallsThrough.consequent[0]);
26
+ const commentInBlock = sourceCode.getCommentsBefore(trailingCloseBrace).pop();
27
+
28
+ if (commentInBlock && fallthroughCommentPattern.test(commentInBlock.value)) {
29
+ return true;
30
+ }
31
+ }
32
+
33
+ const comment = sourceCode.getCommentsBefore(subsequentCase).pop();
23
34
 
24
35
  return Boolean(comment && fallthroughCommentPattern.test(comment.value));
25
36
  }
@@ -108,7 +119,7 @@ module.exports = {
108
119
  * Checks whether or not there is a fallthrough comment.
109
120
  * And reports the previous fallthrough node if that does not exist.
110
121
  */
111
- if (fallthroughCase && !hasFallthroughComment(node, context, fallthroughCommentPattern)) {
122
+ if (fallthroughCase && !hasFallthroughComment(fallthroughCase, node, context, fallthroughCommentPattern)) {
112
123
  context.report({
113
124
  messageId: node.test ? "case" : "default",
114
125
  node
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "7.28.0",
3
+ "version": "7.29.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {