Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'tools/node_modules/eslint/lib/linter')
-rw-r--r--tools/node_modules/eslint/lib/linter/apply-disable-directives.js79
-rw-r--r--tools/node_modules/eslint/lib/linter/linter.js107
2 files changed, 119 insertions, 67 deletions
diff --git a/tools/node_modules/eslint/lib/linter/apply-disable-directives.js b/tools/node_modules/eslint/lib/linter/apply-disable-directives.js
index f6b432399cf..f8e4aeedb29 100644
--- a/tools/node_modules/eslint/lib/linter/apply-disable-directives.js
+++ b/tools/node_modules/eslint/lib/linter/apply-disable-directives.js
@@ -197,62 +197,52 @@ function processUnusedDisableDirectives(allDirectives) {
* 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
+ * 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
@@ -282,13 +272,14 @@ function applyDirectives(options) {
/**
* 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).
@@ -296,8 +287,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
diff --git a/tools/node_modules/eslint/lib/linter/linter.js b/tools/node_modules/eslint/lib/linter/linter.js
index 056f9cec98e..9b9f4919207 100644
--- a/tools/node_modules/eslint/lib/linter/linter.js
+++ b/tools/node_modules/eslint/lib/linter/linter.js
@@ -59,6 +59,7 @@ const globals = require("../../conf/globals");
/** @typedef {import("../shared/types").Environment} Environment */
/** @typedef {import("../shared/types").GlobalConf} GlobalConf */
/** @typedef {import("../shared/types").LintMessage} LintMessage */
+/** @typedef {import("../shared/types").SuppressedLintMessage} SuppressedLintMessage */
/** @typedef {import("../shared/types").ParserOptions} ParserOptions */
/** @typedef {import("../shared/types").LanguageOptions} LanguageOptions */
/** @typedef {import("../shared/types").Processor} Processor */
@@ -77,6 +78,7 @@ const globals = require("../../conf/globals");
* @property {number} line The line number
* @property {number} column The column number
* @property {(string|null)} ruleId The rule ID
+ * @property {string} justification The justification of directive
*/
/**
@@ -84,6 +86,7 @@ const globals = require("../../conf/globals");
* @typedef {Object} LinterInternalSlots
* @property {ConfigArray|null} lastConfigArray The `ConfigArray` instance that the last `verify()` call used.
* @property {SourceCode|null} lastSourceCode The `SourceCode` instance that the last `verify()` call used.
+ * @property {SuppressedLintMessage[]} lastSuppressedMessages The `SuppressedLintMessage[]` instance that the last `verify()` call produced.
* @property {Map<string, Parser>} parserMap The loaded parsers.
* @property {Rules} ruleMap The loaded rules.
*/
@@ -287,11 +290,12 @@ function createLintingProblem(options) {
* @param {token} options.commentToken The Comment token
* @param {string} options.value The value after the directive in the comment
* comment specified no specific rules, so it applies to all rules (e.g. `eslint-disable`)
+ * @param {string} options.justification The justification of the directive
* @param {function(string): {create: Function}} options.ruleMapper A map from rule IDs to defined rules
* @returns {Object} Directives and problems from the comment
*/
function createDisableDirectives(options) {
- const { commentToken, type, value, ruleMapper } = options;
+ const { commentToken, type, value, justification, ruleMapper } = options;
const ruleIds = Object.keys(commentParser.parseListConfig(value));
const directiveRules = ruleIds.length ? ruleIds : [null];
const result = {
@@ -306,9 +310,23 @@ function createDisableDirectives(options) {
// push to directives, if the rule is defined(including null, e.g. /*eslint enable*/)
if (ruleId === null || !!ruleMapper(ruleId)) {
if (type === "disable-next-line") {
- result.directives.push({ parentComment, type, line: commentToken.loc.end.line, column: commentToken.loc.end.column + 1, ruleId });
+ result.directives.push({
+ parentComment,
+ type,
+ line: commentToken.loc.end.line,
+ column: commentToken.loc.end.column + 1,
+ ruleId,
+ justification
+ });
} else {
- result.directives.push({ parentComment, type, line: commentToken.loc.start.line, column: commentToken.loc.start.column + 1, ruleId });
+ result.directives.push({
+ parentComment,
+ type,
+ line: commentToken.loc.start.line,
+ column: commentToken.loc.start.column + 1,
+ ruleId,
+ justification
+ });
}
} else {
result.directiveProblems.push(createLintingProblem({ ruleId, loc: commentToken.loc }));
@@ -318,12 +336,21 @@ function createDisableDirectives(options) {
}
/**
- * Remove the ignored part from a given directive comment and trim it.
- * @param {string} value The comment text to strip.
- * @returns {string} The stripped text.
+ * Extract the directive and the justification from a given directive comment and trim them.
+ * @param {string} value The comment text to extract.
+ * @returns {{directivePart: string, justificationPart: string}} The extracted directive and justification.
*/
-function stripDirectiveComment(value) {
- return value.split(/\s-{2,}\s/u)[0].trim();
+function extractDirectiveComment(value) {
+ const match = /\s-{2,}\s/u.exec(value);
+
+ if (!match) {
+ return { directivePart: value.trim(), justificationPart: "" };
+ }
+
+ const directive = value.slice(0, match.index).trim();
+ const justification = value.slice(match.index + match[0].length).trim();
+
+ return { directivePart: directive, justificationPart: justification };
}
/**
@@ -347,8 +374,9 @@ function getDirectiveComments(ast, ruleMapper, warnInlineConfig) {
});
ast.comments.filter(token => token.type !== "Shebang").forEach(comment => {
- const trimmedCommentText = stripDirectiveComment(comment.value);
- const match = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(trimmedCommentText);
+ const { directivePart, justificationPart } = extractDirectiveComment(comment.value);
+
+ const match = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(directivePart);
if (!match) {
return;
@@ -383,7 +411,7 @@ function getDirectiveComments(ast, ruleMapper, warnInlineConfig) {
return;
}
- const directiveValue = trimmedCommentText.slice(match.index + directiveText.length);
+ const directiveValue = directivePart.slice(match.index + directiveText.length);
switch (directiveText) {
case "eslint-disable":
@@ -391,7 +419,7 @@ function getDirectiveComments(ast, ruleMapper, warnInlineConfig) {
case "eslint-disable-next-line":
case "eslint-disable-line": {
const directiveType = directiveText.slice("eslint-".length);
- const options = { commentToken: comment, type: directiveType, value: directiveValue, ruleMapper };
+ const options = { commentToken: comment, type: directiveType, value: directiveValue, justification: justificationPart, ruleMapper };
const { directives, directiveProblems } = createDisableDirectives(options);
disableDirectives.push(...directives);
@@ -548,7 +576,7 @@ function findEslintEnv(text) {
if (match[0].endsWith("*/")) {
retv = Object.assign(
retv || {},
- commentParser.parseListConfig(stripDirectiveComment(match[1]))
+ commentParser.parseListConfig(extractDirectiveComment(match[1]).directivePart)
);
}
}
@@ -1223,6 +1251,7 @@ class Linter {
cwd: normalizeCwd(cwd),
lastConfigArray: null,
lastSourceCode: null,
+ lastSuppressedMessages: [],
configType, // TODO: Remove after flat config conversion
parserMap: new Map([["espree", espree]]),
ruleMap: new Rules()
@@ -1246,7 +1275,7 @@ class Linter {
* @param {ConfigData} providedConfig An ESLintConfig instance to configure everything.
* @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
* @throws {Error} If during rule execution.
- * @returns {LintMessage[]} The results as an array of messages or an empty array if no messages.
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
*/
_verifyWithoutProcessors(textOrSourceCode, providedConfig, providedOptions) {
const slots = internalSlotsMap.get(this);
@@ -1428,11 +1457,11 @@ class Linter {
configArray.normalizeSync();
}
- return this._verifyWithFlatConfigArray(textOrSourceCode, configArray, options, true);
+ return this._distinguishSuppressedMessages(this._verifyWithFlatConfigArray(textOrSourceCode, configArray, options, true));
}
if (typeof config.extractConfig === "function") {
- return this._verifyWithConfigArray(textOrSourceCode, config, options);
+ return this._distinguishSuppressedMessages(this._verifyWithConfigArray(textOrSourceCode, config, options));
}
}
@@ -1446,9 +1475,9 @@ class Linter {
* So we cannot apply multiple processors.
*/
if (options.preprocess || options.postprocess) {
- return this._verifyWithProcessor(textOrSourceCode, config, options);
+ return this._distinguishSuppressedMessages(this._verifyWithProcessor(textOrSourceCode, config, options));
}
- return this._verifyWithoutProcessors(textOrSourceCode, config, options);
+ return this._distinguishSuppressedMessages(this._verifyWithoutProcessors(textOrSourceCode, config, options));
}
/**
@@ -1457,7 +1486,7 @@ class Linter {
* @param {FlatConfig} config The config array.
* @param {VerifyOptions&ProcessorOptions} options The options.
* @param {FlatConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
- * @returns {LintMessage[]} The found problems.
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
*/
_verifyWithFlatConfigArrayAndProcessor(textOrSourceCode, config, options, configForRecursive) {
const filename = options.filename || "<input>";
@@ -1514,7 +1543,7 @@ class Linter {
* @param {FlatConfig} providedConfig An ESLintConfig instance to configure everything.
* @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
* @throws {Error} If during rule execution.
- * @returns {LintMessage[]} The results as an array of messages or an empty array if no messages.
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
*/
_verifyWithFlatConfigArrayAndWithoutProcessors(textOrSourceCode, providedConfig, providedOptions) {
const slots = internalSlotsMap.get(this);
@@ -1663,7 +1692,7 @@ class Linter {
* @param {string|SourceCode} textOrSourceCode The source code.
* @param {ConfigArray} configArray The config array.
* @param {VerifyOptions&ProcessorOptions} options The options.
- * @returns {LintMessage[]} The found problems.
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
*/
_verifyWithConfigArray(textOrSourceCode, configArray, options) {
debug("With ConfigArray: %s", options.filename);
@@ -1700,7 +1729,7 @@ class Linter {
* @param {VerifyOptions&ProcessorOptions} options The options.
* @param {boolean} [firstCall=false] Indicates if this is being called directly
* from verify(). (TODO: Remove once eslintrc is removed.)
- * @returns {LintMessage[]} The found problems.
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
*/
_verifyWithFlatConfigArray(textOrSourceCode, configArray, options, firstCall = false) {
debug("With flat config: %s", options.filename);
@@ -1740,7 +1769,7 @@ class Linter {
* @param {ConfigData|ExtractedConfig} config The config array.
* @param {VerifyOptions&ProcessorOptions} options The options.
* @param {ConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
- * @returns {LintMessage[]} The found problems.
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
*/
_verifyWithProcessor(textOrSourceCode, config, options, configForRecursive) {
const filename = options.filename || "<input>";
@@ -1793,6 +1822,30 @@ class Linter {
}
/**
+ * Given a list of reported problems, distinguish problems between normal messages and suppressed messages.
+ * The normal messages will be returned and the suppressed messages will be stored as lastSuppressedMessages.
+ * @param {Problem[]} problems A list of reported problems.
+ * @returns {LintMessage[]} A list of LintMessage.
+ */
+ _distinguishSuppressedMessages(problems) {
+ const messages = [];
+ const suppressedMessages = [];
+ const slots = internalSlotsMap.get(this);
+
+ for (const problem of problems) {
+ if (problem.suppressions) {
+ suppressedMessages.push(problem);
+ } else {
+ messages.push(problem);
+ }
+ }
+
+ slots.lastSuppressedMessages = suppressedMessages;
+
+ return messages;
+ }
+
+ /**
* Gets the SourceCode object representing the parsed source.
* @returns {SourceCode} The SourceCode object.
*/
@@ -1801,6 +1854,14 @@ class Linter {
}
/**
+ * Gets the list of SuppressedLintMessage produced in the last running.
+ * @returns {SuppressedLintMessage[]} The list of SuppressedLintMessage
+ */
+ getSuppressedMessages() {
+ return internalSlotsMap.get(this).lastSuppressedMessages;
+ }
+
+ /**
* Defines a new linting rule.
* @param {string} ruleId A unique rule identifier
* @param {Function | Rule} ruleModule Function from context to object mapping AST node types to event handlers