]> git.proxmox.com Git - pve-eslint.git/blobdiff - eslint/lib/linter/apply-disable-directives.js
import 8.41.0 source
[pve-eslint.git] / eslint / lib / linter / apply-disable-directives.js
index e5f2e528ef86ea9f77d8c1292cb30510c4d76994..13ced990ff485dd9425610c9afd03007d7c46ad9 100644 (file)
@@ -5,6 +5,16 @@
 
 "use strict";
 
+//------------------------------------------------------------------------------
+// Typedefs
+//------------------------------------------------------------------------------
+
+/** @typedef {import("../shared/types").LintMessage} LintMessage */
+
+//------------------------------------------------------------------------------
+// Module Definition
+//------------------------------------------------------------------------------
+
 const escapeRegExp = require("escape-string-regexp");
 
 /**
@@ -43,7 +53,7 @@ function groupByParentComment(directives) {
  * Creates removal details for a set of directives within the same comment.
  * @param {Directive[]} directives Unused directives to be removed.
  * @param {Token} commentToken The backing Comment token.
- * @returns {{ description, fix, position }[]} Details for later creation of output Problems.
+ * @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
  */
 function createIndividualDirectivesRemoval(directives, commentToken) {
 
@@ -66,7 +76,7 @@ function createIndividualDirectivesRemoval(directives, commentToken) {
     const listText = commentToken.value
         .slice(listStartOffset) // remove directive name and all whitespace before the list
         .split(/\s-{2,}\s/u)[0] // remove `-- comment`, if it exists
-        .trimRight(); // remove all whitespace after the list
+        .trimEnd(); // remove all whitespace after the list
 
     /*
      * We can assume that `listText` contains multiple elements.
@@ -138,7 +148,7 @@ function createIndividualDirectivesRemoval(directives, commentToken) {
                 ],
                 text: ""
             },
-            position: directive.unprocessedDirective
+            unprocessedDirective: directive.unprocessedDirective
         };
     });
 }
@@ -147,7 +157,7 @@ function createIndividualDirectivesRemoval(directives, commentToken) {
  * Creates a description of deleting an entire unused disable comment.
  * @param {Directive[]} directives Unused directives to be removed.
  * @param {Token} commentToken The backing Comment token.
- * @returns {{ description, fix, position }} Details for later creation of an output Problem.
+ * @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output Problem.
  */
 function createCommentRemoval(directives, commentToken) {
     const { range } = commentToken;
@@ -161,14 +171,14 @@ function createCommentRemoval(directives, commentToken) {
             range,
             text: " "
         },
-        position: directives[0].unprocessedDirective
+        unprocessedDirective: directives[0].unprocessedDirective
     };
 }
 
 /**
  * Parses details from directives to create output Problems.
  * @param {Directive[]} allDirectives Unused directives to be removed.
- * @returns {{ description, fix, position }[]} Details for later creation of output Problems.
+ * @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
  */
 function processUnusedDisableDirectives(allDirectives) {
     const directiveGroups = groupByParentComment(allDirectives);
@@ -196,63 +206,53 @@ function processUnusedDisableDirectives(allDirectives) {
  * @param {Object} options options for applying directives. This is the same as the options
  * for the exported function, except that `reportUnusedDisableDirectives` is not supported
  * (this function always reports unused disable directives).
- * @returns {{problems: Problem[], unusedDisableDirectives: Problem[]}} An object with a list
- * of filtered problems and unused eslint-disable directives
+ * @returns {{problems: LintMessage[], unusedDisableDirectives: LintMessage[]}} An object with a list
+ * of problems (including suppressed ones) and unused eslint-disable directives
  */
 function applyDirectives(options) {
     const problems = [];
-    let nextDirectiveIndex = 0;
-    let currentGlobalDisableDirective = null;
-    const disabledRuleMap = new Map();
-
-    // enabledRules is only used when there is a current global disable directive.
-    const enabledRules = new Set();
     const usedDisableDirectives = new Set();
 
     for (const problem of options.problems) {
+        let disableDirectivesForProblem = [];
+        let nextDirectiveIndex = 0;
+
         while (
             nextDirectiveIndex < options.directives.length &&
             compareLocations(options.directives[nextDirectiveIndex], problem) <= 0
         ) {
             const directive = options.directives[nextDirectiveIndex++];
 
-            switch (directive.type) {
-                case "disable":
-                    if (directive.ruleId === null) {
-                        currentGlobalDisableDirective = directive;
-                        disabledRuleMap.clear();
-                        enabledRules.clear();
-                    } else if (currentGlobalDisableDirective) {
-                        enabledRules.delete(directive.ruleId);
-                        disabledRuleMap.set(directive.ruleId, directive);
-                    } else {
-                        disabledRuleMap.set(directive.ruleId, directive);
-                    }
-                    break;
-
-                case "enable":
-                    if (directive.ruleId === null) {
-                        currentGlobalDisableDirective = null;
-                        disabledRuleMap.clear();
-                    } else if (currentGlobalDisableDirective) {
-                        enabledRules.add(directive.ruleId);
-                        disabledRuleMap.delete(directive.ruleId);
-                    } else {
-                        disabledRuleMap.delete(directive.ruleId);
-                    }
-                    break;
-
-                // no default
+            if (directive.ruleId === null || directive.ruleId === problem.ruleId) {
+                switch (directive.type) {
+                    case "disable":
+                        disableDirectivesForProblem.push(directive);
+                        break;
+
+                    case "enable":
+                        disableDirectivesForProblem = [];
+                        break;
+
+                    // no default
+                }
             }
         }
 
-        if (disabledRuleMap.has(problem.ruleId)) {
-            usedDisableDirectives.add(disabledRuleMap.get(problem.ruleId));
-        } else if (currentGlobalDisableDirective && !enabledRules.has(problem.ruleId)) {
-            usedDisableDirectives.add(currentGlobalDisableDirective);
-        } else {
-            problems.push(problem);
+        if (disableDirectivesForProblem.length > 0) {
+            const suppressions = disableDirectivesForProblem.map(directive => ({
+                kind: "directive",
+                justification: directive.unprocessedDirective.justification
+            }));
+
+            if (problem.suppressions) {
+                problem.suppressions = problem.suppressions.concat(suppressions);
+            } else {
+                problem.suppressions = suppressions;
+                usedDisableDirectives.add(disableDirectivesForProblem[disableDirectivesForProblem.length - 1]);
+            }
         }
+
+        problems.push(problem);
     }
 
     const unusedDisableDirectivesToReport = options.directives
@@ -261,30 +261,35 @@ function applyDirectives(options) {
     const processed = processUnusedDisableDirectives(unusedDisableDirectivesToReport);
 
     const unusedDisableDirectives = processed
-        .map(({ description, fix, position }) => ({
-            ruleId: null,
-            message: description
-                ? `Unused eslint-disable directive (no problems were reported from ${description}).`
-                : "Unused eslint-disable directive (no problems were reported).",
-            line: position.line,
-            column: position.column,
-            severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2,
-            nodeType: null,
-            ...options.disableFixes ? {} : { fix }
-        }));
+        .map(({ description, fix, unprocessedDirective }) => {
+            const { parentComment, type, line, column } = unprocessedDirective;
+
+            return {
+                ruleId: null,
+                message: description
+                    ? `Unused eslint-disable directive (no problems were reported from ${description}).`
+                    : "Unused eslint-disable directive (no problems were reported).",
+                line: type === "disable-next-line" ? parentComment.commentToken.loc.start.line : line,
+                column: type === "disable-next-line" ? parentComment.commentToken.loc.start.column + 1 : column,
+                severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2,
+                nodeType: null,
+                ...options.disableFixes ? {} : { fix }
+            };
+        });
 
     return { problems, unusedDisableDirectives };
 }
 
 /**
  * Given a list of directive comments (i.e. metadata about eslint-disable and eslint-enable comments) and a list
- * of reported problems, determines which problems should be reported.
+ * of reported problems, adds the suppression information to the problems.
  * @param {Object} options Information about directives and problems
  * @param {{
  *      type: ("disable"|"enable"|"disable-line"|"disable-next-line"),
  *      ruleId: (string|null),
  *      line: number,
- *      column: number
+ *      column: number,
+ *      justification: string
  * }} options.directives Directive comments found in the file, with one-based columns.
  * Two directive comments can only have the same location if they also have the same type (e.g. a single eslint-disable
  * comment for two different rules is represented as two directives).
@@ -292,8 +297,8 @@ function applyDirectives(options) {
  * A list of problems reported by rules, sorted by increasing location in the file, with one-based columns.
  * @param {"off" | "warn" | "error"} options.reportUnusedDisableDirectives If `"warn"` or `"error"`, adds additional problems for unused directives
  * @param {boolean} options.disableFixes If true, it doesn't make `fix` properties.
- * @returns {{ruleId: (string|null), line: number, column: number}[]}
- * A list of reported problems that were not disabled by the directive comments.
+ * @returns {{ruleId: (string|null), line: number, column: number, suppressions?: {kind: string, justification: string}}[]}
+ * An object with a list of reported problems, the suppressed of which contain the suppression information.
  */
 module.exports = ({ directives, disableFixes, problems, reportUnusedDisableDirectives = "off" }) => {
     const blockDirectives = directives