123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- /**
- * @author Toru Nagashima <https://github.com/mysticatea>
- * See LICENSE file in root directory for full license.
- */
- "use strict"
- const getLinters = require("../internal/get-linters")
- const { toRuleIdLocation } = require("../internal/utils")
- const quotedName = /'(.+?)'/u
- /**
- * Get the severity of a given rule.
- * @param {object} config The config object to check.
- * @param {string} ruleId The rule ID to check.
- * @returns {number} The severity of the rule.
- */
- function getSeverity(config, ruleId) {
- const rules = config && config.rules
- const ruleOptions = rules && rules[ruleId]
- const severity = Array.isArray(ruleOptions) ? ruleOptions[0] : ruleOptions
- switch (severity) {
- case 2:
- case "error":
- return 2
- case 1:
- case "warn":
- return 1
- default:
- return 0
- }
- }
- /**
- * Get the comment which is at a given message location.
- * @param {Message} message The message to get.
- * @param {SourceCode|undefined} sourceCode The source code object to get.
- * @returns {Comment|undefined} The gotten comment.
- */
- function getCommentAt(message, sourceCode) {
- if (sourceCode != null) {
- const loc = { line: message.line, column: message.column - 1 }
- const index = sourceCode.getIndexFromLoc(loc)
- const options = { includeComments: true }
- const comment = sourceCode.getTokenByRangeStart(index, options)
- if (
- comment != null &&
- (comment.type === "Line" || comment.type === "Block")
- ) {
- return comment
- }
- }
- return undefined
- }
- /**
- * Check whether a given message is a `reportUnusedDisableDirectives` error.
- * @param {Message} message The message.
- * @returns {boolean} `true` if the message is a `reportUnusedDisableDirectives` error.
- */
- function isUnusedDisableDirectiveError(message) {
- return (
- !message.fatal &&
- !message.ruleId &&
- message.message.includes("eslint-disable")
- )
- }
- /**
- * Create `eslint-comments/no-unused-disable` error.
- * @param {string} ruleId The ruleId.
- * @param {number} severity The severity of the rule.
- * @param {Message} message The original message.
- * @param {Comment|undefined} comment The directive comment.
- * @returns {Message} The created error.
- */
- function createNoUnusedDisableError(ruleId, severity, message, comment) {
- const clone = Object.assign({}, message)
- const match = quotedName.exec(message.message)
- const targetRuleId = match && match[1]
- clone.ruleId = ruleId
- clone.severity = severity
- clone.message = targetRuleId
- ? `'${targetRuleId}' rule is disabled but never reported.`
- : "ESLint rules are disabled but never reported."
- clone.suggestions = []
- if (comment != null) {
- if (targetRuleId) {
- const loc = toRuleIdLocation(comment, targetRuleId)
- clone.line = loc.start.line
- clone.column = loc.start.column + 1
- clone.endLine = loc.end.line
- clone.endColumn = loc.end.column + 1
- } else {
- clone.endLine = comment.loc.end.line
- clone.endColumn = comment.loc.end.column + 1
- }
- // Remove the whole node if it is the only rule, otherwise
- // don't try to fix because it is quite complicated.
- if (!comment.value.includes(",") && !comment.value.includes("--")) {
- // We can't use the typical `fixer` helper because we are injecting
- // this message after the fixes are resolved.
- clone.suggestions = [
- {
- desc: "Remove `eslint-disable` comment.",
- fix: {
- range: comment.range,
- text: comment.value.includes("\n") ? "\n" : "",
- },
- },
- ]
- }
- }
- return clone
- }
- /**
- * Convert `reportUnusedDisableDirectives` errors to `eslint-comments/no-unused-disable` errors.
- * @param {Message[]} messages The original messages.
- * @param {SourceCode|undefined} sourceCode The source code object.
- * @param {string} ruleId The rule ID to convert.
- * @param {number} severity The severity of the rule.
- * @param {boolean} keepAsIs The flag to keep original errors as is.
- * @returns {Message[]} The converted messages.
- */
- function convert(messages, sourceCode, ruleId, severity, keepAsIs) {
- for (let i = messages.length - 1; i >= 0; --i) {
- const message = messages[i]
- if (!isUnusedDisableDirectiveError(message)) {
- continue
- }
- const newMessage = createNoUnusedDisableError(
- ruleId,
- severity,
- message,
- getCommentAt(message, sourceCode)
- )
- if (keepAsIs) {
- messages.splice(i + 1, 0, newMessage)
- } else {
- messages.splice(i, 1, newMessage)
- }
- }
- return messages
- }
- module.exports = (ruleId = "eslint-comments/no-unused-disable") => {
- for (const Linter of getLinters()) {
- const verify0 = Linter.prototype._verifyWithoutProcessors
- Object.defineProperty(Linter.prototype, "_verifyWithoutProcessors", {
- value: function _verifyWithoutProcessors(
- textOrSourceCode,
- config,
- filenameOrOptions
- ) {
- const severity = getSeverity(config, ruleId)
- if (severity === 0) {
- return verify0.call(
- this,
- textOrSourceCode,
- config,
- filenameOrOptions
- )
- }
- const options =
- typeof filenameOrOptions === "string"
- ? { filename: filenameOrOptions }
- : filenameOrOptions || {}
- const reportUnusedDisableDirectives = Boolean(
- options.reportUnusedDisableDirectives
- )
- const messages = verify0.call(
- this,
- textOrSourceCode,
- config,
- Object.assign({}, options, {
- reportUnusedDisableDirectives: true,
- })
- )
- return convert(
- messages,
- this.getSourceCode(),
- ruleId,
- severity,
- reportUnusedDisableDirectives
- )
- },
- configurable: true,
- writable: true,
- })
- }
- }
|