eslint 8.55.0 → 8.56.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
@@ -103,7 +103,7 @@ We are now at or near 100% compatibility with JSCS. If you try ESLint and believ
103
103
 
104
104
  ### Does Prettier replace ESLint?
105
105
 
106
- No, ESLint does both traditional linting (looking for problematic patterns) and style checking (enforcement of conventions). You can use ESLint for everything, or you can combine both using Prettier to format your code and ESLint to catch possible errors.
106
+ No, ESLint and Prettier have diffent jobs: ESLint is a linter (looking for problematic patterns) and Prettier is a code formatter. Using both tools is common, refer to [Prettier's documentation](https://prettier.io/docs/en/install#eslint-and-other-linters) to learn how to configure them to work well with each other.
107
107
 
108
108
  ### Why can't ESLint find my plugins?
109
109
 
@@ -209,12 +209,12 @@ The people who manage releases, review feature requests, and meet regularly to e
209
209
 
210
210
  <table><tbody><tr><td align="center" valign="top" width="11%">
211
211
  <a href="https://github.com/nzakas">
212
- <img src="https://github.com/nzakas.png?s=75" width="75" height="75"><br />
212
+ <img src="https://github.com/nzakas.png?s=75" width="75" height="75" alt="Nicholas C. Zakas's Avatar"><br />
213
213
  Nicholas C. Zakas
214
214
  </a>
215
215
  </td><td align="center" valign="top" width="11%">
216
216
  <a href="https://github.com/mdjermanovic">
217
- <img src="https://github.com/mdjermanovic.png?s=75" width="75" height="75"><br />
217
+ <img src="https://github.com/mdjermanovic.png?s=75" width="75" height="75" alt="Milos Djermanovic's Avatar"><br />
218
218
  Milos Djermanovic
219
219
  </a>
220
220
  </td></tr></tbody></table>
@@ -225,12 +225,12 @@ The people who review and implement new features.
225
225
 
226
226
  <table><tbody><tr><td align="center" valign="top" width="11%">
227
227
  <a href="https://github.com/aladdin-add">
228
- <img src="https://github.com/aladdin-add.png?s=75" width="75" height="75"><br />
228
+ <img src="https://github.com/aladdin-add.png?s=75" width="75" height="75" alt="唯然's Avatar"><br />
229
229
  唯然
230
230
  </a>
231
231
  </td><td align="center" valign="top" width="11%">
232
232
  <a href="https://github.com/snitin315">
233
- <img src="https://github.com/snitin315.png?s=75" width="75" height="75"><br />
233
+ <img src="https://github.com/snitin315.png?s=75" width="75" height="75" alt="Nitin Kumar's Avatar"><br />
234
234
  Nitin Kumar
235
235
  </a>
236
236
  </td></tr></tbody></table>
@@ -241,22 +241,22 @@ The people who review and fix bugs and help triage issues.
241
241
 
242
242
  <table><tbody><tr><td align="center" valign="top" width="11%">
243
243
  <a href="https://github.com/bmish">
244
- <img src="https://github.com/bmish.png?s=75" width="75" height="75"><br />
244
+ <img src="https://github.com/bmish.png?s=75" width="75" height="75" alt="Bryan Mishkin's Avatar"><br />
245
245
  Bryan Mishkin
246
246
  </a>
247
247
  </td><td align="center" valign="top" width="11%">
248
248
  <a href="https://github.com/fasttime">
249
- <img src="https://github.com/fasttime.png?s=75" width="75" height="75"><br />
249
+ <img src="https://github.com/fasttime.png?s=75" width="75" height="75" alt="Francesco Trotta's Avatar"><br />
250
250
  Francesco Trotta
251
251
  </a>
252
252
  </td><td align="center" valign="top" width="11%">
253
253
  <a href="https://github.com/ota-meshi">
254
- <img src="https://github.com/ota-meshi.png?s=75" width="75" height="75"><br />
254
+ <img src="https://github.com/ota-meshi.png?s=75" width="75" height="75" alt="Yosuke Ota's Avatar"><br />
255
255
  Yosuke Ota
256
256
  </a>
257
257
  </td><td align="center" valign="top" width="11%">
258
258
  <a href="https://github.com/Tanujkanti4441">
259
- <img src="https://github.com/Tanujkanti4441.png?s=75" width="75" height="75"><br />
259
+ <img src="https://github.com/Tanujkanti4441.png?s=75" width="75" height="75" alt="Tanuj Kanti's Avatar"><br />
260
260
  Tanuj Kanti
261
261
  </a>
262
262
  </td></tr></tbody></table>
@@ -267,17 +267,17 @@ Team members who focus specifically on eslint.org
267
267
 
268
268
  <table><tbody><tr><td align="center" valign="top" width="11%">
269
269
  <a href="https://github.com/amareshsm">
270
- <img src="https://github.com/amareshsm.png?s=75" width="75" height="75"><br />
270
+ <img src="https://github.com/amareshsm.png?s=75" width="75" height="75" alt="Amaresh S M's Avatar"><br />
271
271
  Amaresh S M
272
272
  </a>
273
273
  </td><td align="center" valign="top" width="11%">
274
274
  <a href="https://github.com/harish-sethuraman">
275
- <img src="https://github.com/harish-sethuraman.png?s=75" width="75" height="75"><br />
275
+ <img src="https://github.com/harish-sethuraman.png?s=75" width="75" height="75" alt="Strek's Avatar"><br />
276
276
  Strek
277
277
  </a>
278
278
  </td><td align="center" valign="top" width="11%">
279
279
  <a href="https://github.com/kecrily">
280
- <img src="https://github.com/kecrily.png?s=75" width="75" height="75"><br />
280
+ <img src="https://github.com/kecrily.png?s=75" width="75" height="75" alt="Percy Ma's Avatar"><br />
281
281
  Percy Ma
282
282
  </a>
283
283
  </td></tr></tbody></table>
@@ -293,8 +293,8 @@ The following companies, organizations, and individuals support ESLint's ongoing
293
293
  <h3>Platinum Sponsors</h3>
294
294
  <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>
295
295
  <p><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>
296
- <p><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>
297
- <p><a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" 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" 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></p>
296
+ <p><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> <a href="https://www.workleap.com"><img src="https://avatars.githubusercontent.com/u/53535748?u=d1e55d7661d724bf2281c1bfd33cb8f99fe2465f&v=4" alt="Workleap" height="64"></a></p><h3>Bronze Sponsors</h3>
297
+ <p><a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" 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" 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://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104?v=4" alt="Nx" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a></p>
298
298
  <!--sponsorsend-->
299
299
 
300
300
  ## Technology Sponsors
@@ -83,7 +83,7 @@ const validFixTypes = new Set(["directive", "problem", "suggestion", "layout"]);
83
83
  * @property {string[]} [plugins] An array of plugins to load.
84
84
  * @property {Record<string,RuleConf>} [rules] An object of rules to use.
85
85
  * @property {string[]} [rulePaths] An array of directories to load custom rules from.
86
- * @property {boolean} [reportUnusedDisableDirectives] `true` adds reports for unused eslint-disable directives
86
+ * @property {boolean|string} [reportUnusedDisableDirectives] `true`, `"error"` or '"warn"' adds reports for unused eslint-disable directives
87
87
  * @property {boolean} [globInputPaths] Set to false to skip glob resolution of input file paths to lint (default: true). If false, each input file paths is assumed to be a non-glob path to an existing file.
88
88
  * @property {string} [resolvePluginsRelativeTo] The folder where plugins should be resolved from, defaulting to the CWD
89
89
  */
@@ -224,7 +224,7 @@ function calculateStatsPerRun(results) {
224
224
  * @param {ConfigArray} config.config The config.
225
225
  * @param {boolean} config.fix If `true` then it does fix.
226
226
  * @param {boolean} config.allowInlineConfig If `true` then it uses directive comments.
227
- * @param {boolean} config.reportUnusedDisableDirectives If `true` then it reports unused `eslint-disable` comments.
227
+ * @param {boolean|string} config.reportUnusedDisableDirectives If `true`, `"error"` or '"warn"', then it reports unused `eslint-disable` comments.
228
228
  * @param {FileEnumerator} config.fileEnumerator The file enumerator to check if a path is a target or not.
229
229
  * @param {Linter} config.linter The linter instance to verify.
230
230
  * @returns {LintResult} The result of linting.
package/lib/cli.js CHANGED
@@ -22,7 +22,8 @@ const fs = require("fs"),
22
22
  { FlatESLint, shouldUseFlatConfig } = require("./eslint/flat-eslint"),
23
23
  createCLIOptions = require("./options"),
24
24
  log = require("./shared/logging"),
25
- RuntimeInfo = require("./shared/runtime-info");
25
+ RuntimeInfo = require("./shared/runtime-info"),
26
+ { normalizeSeverityToString } = require("./shared/severity");
26
27
  const { Legacy: { naming } } = require("@eslint/eslintrc");
27
28
  const { ModuleImporter } = require("@humanwhocodes/module-importer");
28
29
 
@@ -89,6 +90,7 @@ async function translateOptions({
89
90
  plugin,
90
91
  quiet,
91
92
  reportUnusedDisableDirectives,
93
+ reportUnusedDisableDirectivesSeverity,
92
94
  resolvePluginsRelativeTo,
93
95
  rule,
94
96
  rulesdir,
@@ -125,6 +127,14 @@ async function translateOptions({
125
127
  rules: rule ? rule : {}
126
128
  }];
127
129
 
130
+ if (reportUnusedDisableDirectives || reportUnusedDisableDirectivesSeverity !== void 0) {
131
+ overrideConfig[0].linterOptions = {
132
+ reportUnusedDisableDirectives: reportUnusedDisableDirectives
133
+ ? "error"
134
+ : normalizeSeverityToString(reportUnusedDisableDirectivesSeverity)
135
+ };
136
+ }
137
+
128
138
  if (parser) {
129
139
  overrideConfig[0].languageOptions.parser = await importer.import(parser);
130
140
  }
@@ -177,8 +187,7 @@ async function translateOptions({
177
187
  fixTypes: fixType,
178
188
  ignore,
179
189
  overrideConfig,
180
- overrideConfigFile,
181
- reportUnusedDisableDirectives: reportUnusedDisableDirectives ? "error" : void 0
190
+ overrideConfigFile
182
191
  };
183
192
 
184
193
  if (configType === "flat") {
@@ -190,6 +199,11 @@ async function translateOptions({
190
199
  options.useEslintrc = eslintrc;
191
200
  options.extensions = ext;
192
201
  options.ignorePath = ignorePath;
202
+ if (reportUnusedDisableDirectives || reportUnusedDisableDirectivesSeverity !== void 0) {
203
+ options.reportUnusedDisableDirectives = reportUnusedDisableDirectives
204
+ ? "error"
205
+ : normalizeSeverityToString(reportUnusedDisableDirectivesSeverity);
206
+ }
193
207
  }
194
208
 
195
209
  return options;
@@ -386,6 +400,11 @@ const cli = {
386
400
  return 2;
387
401
  }
388
402
 
403
+ if (options.reportUnusedDisableDirectives && options.reportUnusedDisableDirectivesSeverity !== void 0) {
404
+ log.error("The --report-unused-disable-directives option and the --report-unused-disable-directives-severity option cannot be used together.");
405
+ return 2;
406
+ }
407
+
389
408
  const ActiveESLint = usingFlatConfig ? FlatESLint : ESLint;
390
409
 
391
410
  const engine = new ActiveESLint(await translateOptions(options, usingFlatConfig ? "flat" : "eslintrc"));
@@ -14,6 +14,7 @@
14
14
  * starting in Node.js v17.
15
15
  */
16
16
  const structuredClone = require("@ungap/structured-clone").default;
17
+ const { normalizeSeverityToNumber } = require("../shared/severity");
17
18
 
18
19
  //-----------------------------------------------------------------------------
19
20
  // Type Definitions
@@ -262,6 +263,26 @@ const booleanSchema = {
262
263
  validate: "boolean"
263
264
  };
264
265
 
266
+ const ALLOWED_SEVERITIES = new Set(["error", "warn", "off", 2, 1, 0]);
267
+
268
+ /** @type {ObjectPropertySchema} */
269
+ const disableDirectiveSeveritySchema = {
270
+ merge(first, second) {
271
+ const value = second === void 0 ? first : second;
272
+
273
+ if (typeof value === "boolean") {
274
+ return value ? "warn" : "off";
275
+ }
276
+
277
+ return normalizeSeverityToNumber(value);
278
+ },
279
+ validate(value) {
280
+ if (!(ALLOWED_SEVERITIES.has(value) || typeof value === "boolean")) {
281
+ throw new TypeError("Expected one of: \"error\", \"warn\", \"off\", 0, 1, 2, or a boolean.");
282
+ }
283
+ }
284
+ };
285
+
265
286
  /** @type {ObjectPropertySchema} */
266
287
  const deepObjectAssignSchema = {
267
288
  merge(first = {}, second = {}) {
@@ -534,7 +555,7 @@ const flatConfigSchema = {
534
555
  linterOptions: {
535
556
  schema: {
536
557
  noInlineConfig: booleanSchema,
537
- reportUnusedDisableDirectives: booleanSchema
558
+ reportUnusedDisableDirectives: disableDirectiveSeveritySchema
538
559
  }
539
560
  },
540
561
  languageOptions: {
@@ -675,7 +675,6 @@ function processOptions({
675
675
  overrideConfig = null,
676
676
  overrideConfigFile = null,
677
677
  plugins = {},
678
- reportUnusedDisableDirectives = null, // ← should be null by default because if it's a string then it overrides the 'reportUnusedDisableDirectives' setting in config files. And we cannot use `overrideConfig.reportUnusedDisableDirectives` instead because we cannot configure the `error` severity with that.
679
678
  warnIgnored = true,
680
679
  ...unknownOptions
681
680
  }) {
@@ -720,6 +719,9 @@ function processOptions({
720
719
  if (unknownOptionKeys.includes("rulePaths")) {
721
720
  errors.push("'rulePaths' has been removed. Please define your rules using plugins.");
722
721
  }
722
+ if (unknownOptionKeys.includes("reportUnusedDisableDirectives")) {
723
+ errors.push("'reportUnusedDisableDirectives' has been removed. Please use the 'overrideConfig.linterOptions.reportUnusedDisableDirectives' option instead.");
724
+ }
723
725
  }
724
726
  if (typeof allowInlineConfig !== "boolean") {
725
727
  errors.push("'allowInlineConfig' must be a boolean.");
@@ -774,14 +776,6 @@ function processOptions({
774
776
  if (Array.isArray(plugins)) {
775
777
  errors.push("'plugins' doesn't add plugins to configuration to load. Please use the 'overrideConfig.plugins' option instead.");
776
778
  }
777
- if (
778
- reportUnusedDisableDirectives !== "error" &&
779
- reportUnusedDisableDirectives !== "warn" &&
780
- reportUnusedDisableDirectives !== "off" &&
781
- reportUnusedDisableDirectives !== null
782
- ) {
783
- errors.push("'reportUnusedDisableDirectives' must be any of \"error\", \"warn\", \"off\", and null.");
784
- }
785
779
  if (typeof warnIgnored !== "boolean") {
786
780
  errors.push("'warnIgnored' must be a boolean.");
787
781
  }
@@ -806,7 +800,6 @@ function processOptions({
806
800
  globInputPaths,
807
801
  ignore,
808
802
  ignorePatterns,
809
- reportUnusedDisableDirectives,
810
803
  warnIgnored
811
804
  };
812
805
  }
@@ -11,6 +11,7 @@
11
11
 
12
12
  // Note: Node.js 12 does not support fs/promises.
13
13
  const fs = require("fs").promises;
14
+ const { existsSync } = require("fs");
14
15
  const path = require("path");
15
16
  const findUp = require("find-up");
16
17
  const { version } = require("../../package.json");
@@ -83,7 +84,6 @@ const LintResultCache = require("../cli-engine/lint-result-cache");
83
84
  * doesn't do any config file lookup when `true`; considered to be a config filename
84
85
  * when a string.
85
86
  * @property {Record<string,Plugin>} [plugins] An array of plugin implementations.
86
- * @property {"error" | "warn" | "off"} [reportUnusedDisableDirectives] the severity to report unused eslint-disable directives.
87
87
  * @property {boolean} warnIgnored Show warnings when the file list includes ignored files
88
88
  */
89
89
 
@@ -448,7 +448,6 @@ async function calculateConfigArray(eslint, {
448
448
  * @param {FlatConfigArray} config.configs The config.
449
449
  * @param {boolean} config.fix If `true` then it does fix.
450
450
  * @param {boolean} config.allowInlineConfig If `true` then it uses directive comments.
451
- * @param {boolean} config.reportUnusedDisableDirectives If `true` then it reports unused `eslint-disable` comments.
452
451
  * @param {Linter} config.linter The linter instance to verify.
453
452
  * @returns {LintResult} The result of linting.
454
453
  * @private
@@ -460,7 +459,6 @@ function verifyText({
460
459
  configs,
461
460
  fix,
462
461
  allowInlineConfig,
463
- reportUnusedDisableDirectives,
464
462
  linter
465
463
  }) {
466
464
  const filePath = providedFilePath || "<text>";
@@ -480,7 +478,6 @@ function verifyText({
480
478
  allowInlineConfig,
481
479
  filename: filePathToVerify,
482
480
  fix,
483
- reportUnusedDisableDirectives,
484
481
 
485
482
  /**
486
483
  * Check if the linter should adopt a given code block or not.
@@ -748,7 +745,6 @@ class FlatESLint {
748
745
  cwd,
749
746
  fix,
750
747
  fixTypes,
751
- reportUnusedDisableDirectives,
752
748
  globInputPaths,
753
749
  errorOnUnmatchedPattern,
754
750
  warnIgnored
@@ -766,7 +762,7 @@ class FlatESLint {
766
762
  const errorCode = error && error.code;
767
763
 
768
764
  // Ignore errors when no such file exists or file system is read only (and cache file does not exist)
769
- if (errorCode !== "ENOENT" && !(errorCode === "EROFS" && !(await fs.exists(cacheFilePath)))) {
765
+ if (errorCode !== "ENOENT" && !(errorCode === "EROFS" && !existsSync(cacheFilePath))) {
770
766
  throw error;
771
767
  }
772
768
  }
@@ -858,7 +854,6 @@ class FlatESLint {
858
854
  cwd,
859
855
  fix: fixer,
860
856
  allowInlineConfig,
861
- reportUnusedDisableDirectives,
862
857
  linter
863
858
  });
864
859
 
@@ -943,7 +938,6 @@ class FlatESLint {
943
938
  allowInlineConfig,
944
939
  cwd,
945
940
  fix,
946
- reportUnusedDisableDirectives,
947
941
  warnIgnored: constructorWarnIgnored
948
942
  } = eslintOptions;
949
943
  const results = [];
@@ -967,7 +961,6 @@ class FlatESLint {
967
961
  cwd,
968
962
  fix,
969
963
  allowInlineConfig,
970
- reportUnusedDisableDirectives,
971
964
  linter
972
965
  }));
973
966
  }
@@ -15,7 +15,10 @@ const levn = require("levn"),
15
15
  Legacy: {
16
16
  ConfigOps
17
17
  }
18
- } = require("@eslint/eslintrc/universal");
18
+ } = require("@eslint/eslintrc/universal"),
19
+ {
20
+ directivesPattern
21
+ } = require("../shared/directives");
19
22
 
20
23
  const debug = require("debug")("eslint:config-comment-parser");
21
24
 
@@ -148,4 +151,35 @@ module.exports = class ConfigCommentParser {
148
151
  return items;
149
152
  }
150
153
 
154
+ /**
155
+ * Extract the directive and the justification from a given directive comment and trim them.
156
+ * @param {string} value The comment text to extract.
157
+ * @returns {{directivePart: string, justificationPart: string}} The extracted directive and justification.
158
+ */
159
+ extractDirectiveComment(value) {
160
+ const match = /\s-{2,}\s/u.exec(value);
161
+
162
+ if (!match) {
163
+ return { directivePart: value.trim(), justificationPart: "" };
164
+ }
165
+
166
+ const directive = value.slice(0, match.index).trim();
167
+ const justification = value.slice(match.index + match[0].length).trim();
168
+
169
+ return { directivePart: directive, justificationPart: justification };
170
+ }
171
+
172
+ /**
173
+ * Parses a directive comment into directive text and value.
174
+ * @param {Comment} comment The comment node with the directive to be parsed.
175
+ * @returns {{directiveText: string, directiveValue: string}} The directive text and value.
176
+ */
177
+ parseDirective(comment) {
178
+ const { directivePart } = this.extractDirectiveComment(comment.value);
179
+ const match = directivesPattern.exec(directivePart);
180
+ const directiveText = match[1];
181
+ const directiveValue = directivePart.slice(match.index + directiveText.length);
182
+
183
+ return { directiveText, directiveValue };
184
+ }
151
185
  };
@@ -44,6 +44,7 @@ const { getRuleFromConfig } = require("../config/flat-config-helpers");
44
44
  const { FlatConfigArray } = require("../config/flat-config-array");
45
45
  const { RuleValidator } = require("../config/rule-validator");
46
46
  const { assertIsRuleOptions, assertIsRuleSeverity } = require("../config/flat-config-schema");
47
+ const { normalizeSeverityToString } = require("../shared/severity");
47
48
  const debug = require("debug")("eslint:linter");
48
49
  const MAX_AUTOFIX_PASSES = 10;
49
50
  const DEFAULT_PARSER_NAME = "espree";
@@ -316,24 +317,6 @@ function createDisableDirectives(options) {
316
317
  return result;
317
318
  }
318
319
 
319
- /**
320
- * Extract the directive and the justification from a given directive comment and trim them.
321
- * @param {string} value The comment text to extract.
322
- * @returns {{directivePart: string, justificationPart: string}} The extracted directive and justification.
323
- */
324
- function extractDirectiveComment(value) {
325
- const match = /\s-{2,}\s/u.exec(value);
326
-
327
- if (!match) {
328
- return { directivePart: value.trim(), justificationPart: "" };
329
- }
330
-
331
- const directive = value.slice(0, match.index).trim();
332
- const justification = value.slice(match.index + match[0].length).trim();
333
-
334
- return { directivePart: directive, justificationPart: justification };
335
- }
336
-
337
320
  /**
338
321
  * Parses comments in file to extract file-specific config of rules, globals
339
322
  * and environments and merges them with global config; also code blocks
@@ -355,7 +338,7 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig) {
355
338
  });
356
339
 
357
340
  sourceCode.getInlineConfigNodes().filter(token => token.type !== "Shebang").forEach(comment => {
358
- const { directivePart, justificationPart } = extractDirectiveComment(comment.value);
341
+ const { directivePart, justificationPart } = commentParser.extractDirectiveComment(comment.value);
359
342
 
360
343
  const match = directivesPattern.exec(directivePart);
361
344
 
@@ -500,7 +483,7 @@ function getDirectiveCommentsForFlatConfig(sourceCode, ruleMapper) {
500
483
  const disableDirectives = [];
501
484
 
502
485
  sourceCode.getInlineConfigNodes().filter(token => token.type !== "Shebang").forEach(comment => {
503
- const { directivePart, justificationPart } = extractDirectiveComment(comment.value);
486
+ const { directivePart, justificationPart } = commentParser.extractDirectiveComment(comment.value);
504
487
 
505
488
  const match = directivesPattern.exec(directivePart);
506
489
 
@@ -620,7 +603,7 @@ function findEslintEnv(text) {
620
603
  if (match[0].endsWith("*/")) {
621
604
  retv = Object.assign(
622
605
  retv || {},
623
- commentParser.parseListConfig(extractDirectiveComment(match[1]).directivePart)
606
+ commentParser.parseListConfig(commentParser.extractDirectiveComment(match[1]).directivePart)
624
607
  );
625
608
  }
626
609
  }
@@ -671,9 +654,11 @@ function normalizeVerifyOptions(providedOptions, config) {
671
654
  reportUnusedDisableDirectives = reportUnusedDisableDirectives ? "error" : "off";
672
655
  }
673
656
  if (typeof reportUnusedDisableDirectives !== "string") {
674
- reportUnusedDisableDirectives =
675
- linterOptions.reportUnusedDisableDirectives
676
- ? "warn" : "off";
657
+ if (typeof linterOptions.reportUnusedDisableDirectives === "boolean") {
658
+ reportUnusedDisableDirectives = linterOptions.reportUnusedDisableDirectives ? "warn" : "off";
659
+ } else {
660
+ reportUnusedDisableDirectives = linterOptions.reportUnusedDisableDirectives === void 0 ? "off" : normalizeSeverityToString(linterOptions.reportUnusedDisableDirectives);
661
+ }
677
662
  }
678
663
 
679
664
  return {
package/lib/options.js CHANGED
@@ -48,6 +48,7 @@ const optionator = require("optionator");
48
48
  * @property {string[]} [plugin] Specify plugins
49
49
  * @property {string} [printConfig] Print the configuration for the given file
50
50
  * @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable and eslint-enable directives
51
+ * @property {string | undefined} reportUnusedDisableDirectivesSeverity A severity string indicating if and how unused disable and enable directives should be tracked and reported.
51
52
  * @property {string} [resolvePluginsRelativeTo] A folder where plugins should be resolved from, CWD by default
52
53
  * @property {Object} [rule] Specify rules
53
54
  * @property {string[]} [rulesdir] Load additional rules from this directory. Deprecated: Use rules from plugins
@@ -306,6 +307,13 @@ module.exports = function(usingFlatConfig) {
306
307
  default: void 0,
307
308
  description: "Adds reported errors for unused eslint-disable and eslint-enable directives"
308
309
  },
310
+ {
311
+ option: "report-unused-disable-directives-severity",
312
+ type: "String",
313
+ default: void 0,
314
+ description: "Chooses severity level for reporting unused eslint-disable and eslint-enable directives",
315
+ enum: ["off", "warn", "error", "0", "1", "2"]
316
+ },
309
317
  {
310
318
  heading: "Caching"
311
319
  },
@@ -96,7 +96,7 @@ module.exports = {
96
96
 
97
97
  if (codePath.origin === "program") {
98
98
  const scope = sourceCode.getScope(node);
99
- const features = context.parserOptions.ecmaFeatures || {};
99
+ const features = context.languageOptions.parserOptions.ecmaFeatures || {};
100
100
 
101
101
  // `this` at the top level of scripts always refers to the global object
102
102
  stack.push({
@@ -209,12 +209,15 @@ module.exports = {
209
209
  });
210
210
  }
211
211
 
212
- suggest.push({
213
- messageId: "wrapBraces",
214
- fix(fixer) {
215
- return curlyWrapFixer(sourceCode, node, fixer);
216
- }
217
- });
212
+ // Do not suggest wrapping an unnamed FunctionExpression in braces as that would be invalid syntax.
213
+ if (!(node.body.type === "FunctionExpression" && !node.body.id)) {
214
+ suggest.push({
215
+ messageId: "wrapBraces",
216
+ fix(fixer) {
217
+ return curlyWrapFixer(sourceCode, node, fixer);
218
+ }
219
+ });
220
+ }
218
221
 
219
222
  context.report({
220
223
  node: node.body,
@@ -142,40 +142,27 @@ module.exports = {
142
142
  }
143
143
  }
144
144
 
145
- /**
146
- * Checks property accesses in a destructuring assignment expression, e.g. `var foo; ({foo} = bar);`
147
- * @param {ASTNode} node An AssignmentExpression or AssignmentPattern node
148
- * @returns {undefined}
149
- */
150
- function checkDestructuringAssignment(node) {
151
- if (node.right.type === "Identifier") {
152
- const objectName = node.right.name;
153
-
154
- if (node.left.type === "ObjectPattern") {
155
- node.left.properties.forEach(property => {
156
- checkPropertyAccess(node.left, objectName, astUtils.getStaticPropertyName(property));
157
- });
158
- }
159
- }
160
- }
161
-
162
145
  return {
163
146
  MemberExpression(node) {
164
147
  checkPropertyAccess(node, node.object && node.object.name, astUtils.getStaticPropertyName(node));
165
148
  },
166
- VariableDeclarator(node) {
167
- if (node.init && node.init.type === "Identifier") {
168
- const objectName = node.init.name;
169
-
170
- if (node.id.type === "ObjectPattern") {
171
- node.id.properties.forEach(property => {
172
- checkPropertyAccess(node.id, objectName, astUtils.getStaticPropertyName(property));
173
- });
149
+ ObjectPattern(node) {
150
+ let objectName = null;
151
+
152
+ if (node.parent.type === "VariableDeclarator") {
153
+ if (node.parent.init && node.parent.init.type === "Identifier") {
154
+ objectName = node.parent.init.name;
155
+ }
156
+ } else if (node.parent.type === "AssignmentExpression" || node.parent.type === "AssignmentPattern") {
157
+ if (node.parent.right.type === "Identifier") {
158
+ objectName = node.parent.right.name;
174
159
  }
175
160
  }
176
- },
177
- AssignmentExpression: checkDestructuringAssignment,
178
- AssignmentPattern: checkDestructuringAssignment
161
+
162
+ node.properties.forEach(property => {
163
+ checkPropertyAccess(node, objectName, astUtils.getStaticPropertyName(property));
164
+ });
165
+ }
179
166
  };
180
167
  }
181
168
  };
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @fileoverview Helpers for severity values (e.g. normalizing different types).
3
+ * @author Bryan Mishkin
4
+ */
5
+
6
+ "use strict";
7
+
8
+ /**
9
+ * Convert severity value of different types to a string.
10
+ * @param {string|number} severity severity value
11
+ * @throws error if severity is invalid
12
+ * @returns {string} severity string
13
+ */
14
+ function normalizeSeverityToString(severity) {
15
+ if ([2, "2", "error"].includes(severity)) {
16
+ return "error";
17
+ }
18
+ if ([1, "1", "warn"].includes(severity)) {
19
+ return "warn";
20
+ }
21
+ if ([0, "0", "off"].includes(severity)) {
22
+ return "off";
23
+ }
24
+ throw new Error(`Invalid severity value: ${severity}`);
25
+ }
26
+
27
+ /**
28
+ * Convert severity value of different types to a number.
29
+ * @param {string|number} severity severity value
30
+ * @throws error if severity is invalid
31
+ * @returns {number} severity number
32
+ */
33
+ function normalizeSeverityToNumber(severity) {
34
+ if ([2, "2", "error"].includes(severity)) {
35
+ return 2;
36
+ }
37
+ if ([1, "1", "warn"].includes(severity)) {
38
+ return 1;
39
+ }
40
+ if ([0, "0", "off"].includes(severity)) {
41
+ return 0;
42
+ }
43
+ throw new Error(`Invalid severity value: ${severity}`);
44
+ }
45
+
46
+ module.exports = {
47
+ normalizeSeverityToString,
48
+ normalizeSeverityToNumber
49
+ };
@@ -212,24 +212,6 @@ function isSpaceBetween(sourceCode, first, second, checkInsideOfJSXText) {
212
212
  // Directive Comments
213
213
  //-----------------------------------------------------------------------------
214
214
 
215
- /**
216
- * Extract the directive and the justification from a given directive comment and trim them.
217
- * @param {string} value The comment text to extract.
218
- * @returns {{directivePart: string, justificationPart: string}} The extracted directive and justification.
219
- */
220
- function extractDirectiveComment(value) {
221
- const match = /\s-{2,}\s/u.exec(value);
222
-
223
- if (!match) {
224
- return { directivePart: value.trim(), justificationPart: "" };
225
- }
226
-
227
- const directive = value.slice(0, match.index).trim();
228
- const justification = value.slice(match.index + match[0].length).trim();
229
-
230
- return { directivePart: directive, justificationPart: justification };
231
- }
232
-
233
215
  /**
234
216
  * Ensures that variables representing built-in properties of the Global Object,
235
217
  * and any globals declared by special block comments, are present in the global
@@ -921,7 +903,7 @@ class SourceCode extends TokenStore {
921
903
  return false;
922
904
  }
923
905
 
924
- const { directivePart } = extractDirectiveComment(comment.value);
906
+ const { directivePart } = commentParser.extractDirectiveComment(comment.value);
925
907
 
926
908
  const directiveMatch = directivesPattern.exec(directivePart);
927
909
 
@@ -977,10 +959,7 @@ class SourceCode extends TokenStore {
977
959
 
978
960
  this.getInlineConfigNodes().forEach(comment => {
979
961
 
980
- const { directivePart } = extractDirectiveComment(comment.value);
981
- const match = directivesPattern.exec(directivePart);
982
- const directiveText = match[1];
983
- const directiveValue = directivePart.slice(match.index + directiveText.length);
962
+ const { directiveText, directiveValue } = commentParser.parseDirective(comment);
984
963
 
985
964
  switch (directiveText) {
986
965
  case "exported":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "8.55.0",
3
+ "version": "8.56.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {
@@ -65,7 +65,7 @@
65
65
  "@eslint-community/eslint-utils": "^4.2.0",
66
66
  "@eslint-community/regexpp": "^4.6.1",
67
67
  "@eslint/eslintrc": "^2.1.4",
68
- "@eslint/js": "8.55.0",
68
+ "@eslint/js": "8.56.0",
69
69
  "@humanwhocodes/config-array": "^0.11.13",
70
70
  "@humanwhocodes/module-importer": "^1.0.1",
71
71
  "@nodelib/fs.walk": "^1.2.8",
@@ -119,11 +119,11 @@
119
119
  "eslint": "file:.",
120
120
  "eslint-config-eslint": "file:packages/eslint-config-eslint",
121
121
  "eslint-plugin-eslint-comments": "^3.2.0",
122
- "eslint-plugin-eslint-plugin": "^5.1.0",
122
+ "eslint-plugin-eslint-plugin": "^5.2.1",
123
123
  "eslint-plugin-internal-rules": "file:tools/internal-rules",
124
124
  "eslint-plugin-jsdoc": "^46.2.5",
125
- "eslint-plugin-n": "^16.0.0",
126
- "eslint-plugin-unicorn": "^42.0.0",
125
+ "eslint-plugin-n": "^16.4.0",
126
+ "eslint-plugin-unicorn": "^49.0.0",
127
127
  "eslint-release": "^3.2.0",
128
128
  "eslump": "^3.0.0",
129
129
  "esprima": "^4.0.1",
@@ -136,7 +136,7 @@
136
136
  "load-perf": "^0.2.0",
137
137
  "markdown-it": "^12.2.0",
138
138
  "markdown-it-container": "^3.0.0",
139
- "markdownlint": "^0.31.1",
139
+ "markdownlint": "^0.32.0",
140
140
  "markdownlint-cli": "^0.37.0",
141
141
  "marked": "^4.0.8",
142
142
  "memfs": "^3.0.1",