From 027e20c1f120f0616bd54c6b68dbb0448ca5ae4d Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Sun, 17 May 2020 14:20:11 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20`eslint-disab?= =?UTF-8?q?le-line`=20block=20comments=20and=20directive=20comments=20with?= =?UTF-8?q?=20descriptions.=20(#43)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/internal/disabled-area.js | 36 ++-- lib/internal/utils.js | 54 +++++ lib/rules/no-unlimited-disable.js | 24 ++- lib/rules/no-use.js | 13 +- package.json | 1 + tests/lib/illegal-eslint-disable-line.js | 98 +++++++++ tests/lib/rules/disable-enable-pair.js | 40 ++++ tests/lib/rules/no-aggregating-enable.js | 17 ++ tests/lib/rules/no-duplicate-disable.js | 77 ++++++++ tests/lib/rules/no-restricted-disable.js | 54 +++++ tests/lib/rules/no-unlimited-disable.js | 46 +++++ tests/lib/rules/no-unused-disable.js | 242 +++++++++++++++++++++++ tests/lib/rules/no-unused-enable.js | 20 ++ tests/lib/rules/no-use.js | 18 +- 14 files changed, 704 insertions(+), 36 deletions(-) create mode 100644 tests/lib/illegal-eslint-disable-line.js diff --git a/lib/internal/disabled-area.js b/lib/internal/disabled-area.js index 71ce9ba..bad87a8 100644 --- a/lib/internal/disabled-area.js +++ b/lib/internal/disabled-area.js @@ -5,7 +5,6 @@ "use strict" const utils = require("./utils") -const COMMENT_DIRECTIVE = /^\s*(eslint-(?:en|dis)able(?:(?:-next)?-line)?)\s*(?:(\S|\S[\s\S]*\S)\s*)?$/u const DELIMITER = /[\s,]+/gu const pool = new WeakMap() @@ -162,7 +161,7 @@ module.exports = class DisabledArea { } /** - * Scan the souce code and setup disabled area list. + * Scan the source code and setup disabled area list. * * @param {eslint.SourceCode} sourceCode - The source code to scan. * @returns {void} @@ -170,31 +169,36 @@ module.exports = class DisabledArea { */ _scan(sourceCode) { for (const comment of sourceCode.getAllComments()) { - const m = COMMENT_DIRECTIVE.exec(comment.value) - if (m == null) { + const directiveComment = utils.parseDirectiveComment(comment) + if (directiveComment == null) { continue } - const kind = m[1] - const ruleIds = m[2] ? m[2].split(DELIMITER) : null - if (comment.type === "Block" && kind === "eslint-disable") { + const kind = directiveComment.kind + if ( + kind !== "eslint-disable" && + kind !== "eslint-enable" && + kind !== "eslint-disable-line" && + kind !== "eslint-disable-next-line" + ) { + continue + } + const ruleIds = directiveComment.value + ? directiveComment.value.split(DELIMITER) + : null + + if (kind === "eslint-disable") { this._disable(comment, comment.loc.start, ruleIds, "block") - } else if (comment.type === "Block" && kind === "eslint-enable") { + } else if (kind === "eslint-enable") { this._enable(comment, comment.loc.start, ruleIds, "block") - } else if ( - comment.type === "Line" && - kind === "eslint-disable-line" - ) { + } else if (kind === "eslint-disable-line") { const line = comment.loc.start.line const start = { line, column: 0 } const end = { line: line + 1, column: -1 } this._disable(comment, start, ruleIds, "line") this._enable(comment, end, ruleIds, "line") - } else if ( - comment.type === "Line" && - kind === "eslint-disable-next-line" - ) { + } else if (kind === "eslint-disable-next-line") { const line = comment.loc.start.line const start = { line: line + 1, column: 0 } const end = { line: line + 2, column: -1 } diff --git a/lib/internal/utils.js b/lib/internal/utils.js index 2d9ef59..849bb04 100644 --- a/lib/internal/utils.js +++ b/lib/internal/utils.js @@ -7,6 +7,9 @@ const escapeStringRegexp = require("escape-string-regexp") const LINE_PATTERN = /[^\r\n\u2028\u2029]*(?:\r\n|[\r\n\u2028\u2029]|$)/gu +const DIRECTIVE_PATTERN = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u +const LINE_COMMENT_PATTERN = /^eslint-disable-(next-)?line$/u + module.exports = { /** * Make the location ignoring `eslint-disable` comments. @@ -95,4 +98,55 @@ module.exports = { lte(a, b) { return a.line < b.line || (a.line === b.line && a.column <= b.column) }, + + /** + * Parse the given comment token as a directive comment. + * + * @param {Token} comment - The comment token to parse. + * @returns {{kind: string, value: string, description: string | null}|null} The parsed data of the given comment. If `null`, it is not a directive comment. + */ + parseDirectiveComment(comment) { + const { text, description } = divideDirectiveComment(comment.value) + const match = DIRECTIVE_PATTERN.exec(text) + + if (!match) { + return null + } + const directiveText = match[1] + const lineCommentSupported = LINE_COMMENT_PATTERN.test(directiveText) + + if (comment.type === "Line" && !lineCommentSupported) { + return null + } + + if ( + lineCommentSupported && + comment.loc.start.line !== comment.loc.end.line + ) { + // disable-line comment should not span multiple lines. + return null + } + + const directiveValue = text.slice(match.index + directiveText.length) + + return { + kind: directiveText, + value: directiveValue.trim(), + description, + } + }, +} + +/** + * Divides and trims description text and directive comments. + * @param {string} value The comment text to strip. + * @returns {{text: string, description: string | null}} The stripped text. + */ +function divideDirectiveComment(value) { + const divided = value.split(/\s-{2,}\s/u) + const text = divided[0].trim() + return { + text, + description: divided.length > 1 ? divided[1].trim() : null, + } } diff --git a/lib/rules/no-unlimited-disable.js b/lib/rules/no-unlimited-disable.js index 1351c17..6c7683e 100644 --- a/lib/rules/no-unlimited-disable.js +++ b/lib/rules/no-unlimited-disable.js @@ -6,11 +6,6 @@ const utils = require("../internal/utils") -const PATTERNS = { - Block: /^\s*(eslint-disable)\s*(\S)?/u, - Line: /^\s*(eslint-disable(?:-next)?-line)\s*(\S)?/u, -} - module.exports = { meta: { docs: { @@ -32,18 +27,27 @@ module.exports = { return { Program() { for (const comment of sourceCode.getAllComments()) { - const pattern = PATTERNS[comment.type] - if (pattern == null) { + const directiveComment = utils.parseDirectiveComment( + comment + ) + if (directiveComment == null) { continue } - const m = pattern.exec(comment.value) - if (m && !m[2]) { + const kind = directiveComment.kind + if ( + kind !== "eslint-disable" && + kind !== "eslint-disable-line" && + kind !== "eslint-disable-next-line" + ) { + continue + } + if (!directiveComment.value) { context.report({ loc: utils.toForceLocation(comment.loc), message: "Unexpected unlimited '{{kind}}' comment. Specify some rule names to disable.", - data: { kind: m[1] }, + data: { kind: directiveComment.kind }, }) } } diff --git a/lib/rules/no-use.js b/lib/rules/no-use.js index dde6fc7..cf9c1d9 100644 --- a/lib/rules/no-use.js +++ b/lib/rules/no-use.js @@ -5,10 +5,6 @@ "use strict" const utils = require("../internal/utils") -const PATTERNS = { - Block: /^\s*(eslint(?:-disable|-enable|-env)?|exported|globals?)(?:\s|$)/u, - Line: /^\s*(eslint-disable(?:-next)?-line)(?:\s|$)/u, -} module.exports = { meta: { @@ -58,13 +54,14 @@ module.exports = { return { Program() { for (const comment of sourceCode.getAllComments()) { - const pattern = PATTERNS[comment.type] - if (pattern == null) { + const directiveComment = utils.parseDirectiveComment( + comment + ) + if (directiveComment == null) { continue } - const m = pattern.exec(comment.value) - if (m != null && !allowed.has(m[1])) { + if (!allowed.has(directiveComment.kind)) { context.report({ loc: utils.toForceLocation(comment.loc), message: "Unexpected ESLint directive comment.", diff --git a/package.json b/package.json index 22897ba..25ac4cf 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "nyc": "^14.1.1", "opener": "^1.4.3", "rimraf": "^2.6.2", + "semver": "^7.3.2", "string-replace-loader": "^2.1.1", "vue-eslint-editor": "^1.1.0", "vuepress": "^1.0.1" diff --git a/tests/lib/illegal-eslint-disable-line.js b/tests/lib/illegal-eslint-disable-line.js new file mode 100644 index 0000000..d6e68cf --- /dev/null +++ b/tests/lib/illegal-eslint-disable-line.js @@ -0,0 +1,98 @@ +/** + * Test that multi-line eslint-disable-line comments are not false positives. + */ +"use strict" + +const assert = require("assert") +const fs = require("fs") +const path = require("path") +const spawn = require("cross-spawn") +const rimraf = require("rimraf") +const semver = require("semver") +const eslintVersion = require("eslint/package").version + +/** + * Run eslint CLI command with a given source code. + * @param {string} code The source code to lint. + * @returns {Promise} The result message. + */ +function runESLint(code) { + return new Promise((resolve, reject) => { + const cp = spawn( + "eslint", + [ + "--stdin", + "--stdin-filename", + "test.js", + "--no-eslintrc", + "--plugin", + "eslint-comments", + "--format", + "json", + ], + { stdio: ["pipe", "pipe", "inherit"] } + ) + const chunks = [] + let totalLength = 0 + + cp.stdout.on("data", chunk => { + chunks.push(chunk) + totalLength += chunk.length + }) + cp.stdout.on("end", () => { + try { + const resultsStr = String(Buffer.concat(chunks, totalLength)) + const results = JSON.parse(resultsStr) + resolve(results[0].messages) + } catch (error) { + reject(error) + } + }) + cp.on("error", reject) + + cp.stdin.end(code) + }) +} + +describe("multi-line eslint-disable-line comments", () => { + before(() => { + // Register this plugin. + const selfPath = path.resolve(__dirname, "../../") + const pluginPath = path.resolve( + __dirname, + "../../node_modules/eslint-plugin-eslint-comments" + ) + + if (fs.existsSync(pluginPath)) { + rimraf.sync(pluginPath) + } + fs.symlinkSync(selfPath, pluginPath, "junction") + }) + + describe("`eslint-comments/*` rules are valid", () => { + for (const code of [ + `/* eslint eslint-comments/no-use:[error, {allow: ['eslint']}] */ +/* eslint-disable-line +*/ +/* eslint-disable-next-line +*/`, + `/* eslint eslint-comments/no-duplicate-disable:error */ +/*eslint-disable no-undef*/ +/*eslint-disable-line +no-undef*/ +`, + ]) { + it(code, () => + runESLint(code).then(messages => { + if (semver.satisfies(eslintVersion, ">=5.0.0")) { + assert.strictEqual(messages.length > 0, true) + } + const normalMessages = messages.filter( + message => message.ruleId != null + ) + assert.strictEqual(normalMessages.length, 0) + }) + ) + } + }) +}) diff --git a/tests/lib/rules/disable-enable-pair.js b/tests/lib/rules/disable-enable-pair.js index f918f1f..a64bb67 100644 --- a/tests/lib/rules/disable-enable-pair.js +++ b/tests/lib/rules/disable-enable-pair.js @@ -4,6 +4,8 @@ */ "use strict" +const semver = require("semver") +const eslintVersion = require("eslint/package").version const RuleTester = require("eslint").RuleTester const rule = require("../../../lib/rules/disable-enable-pair") const tester = new RuleTester() @@ -24,6 +26,8 @@ tester.run("disable-enable-pair", rule, { `, "//eslint-disable-line", "//eslint-disable-next-line", + "/*eslint-disable-line*/", + "/*eslint-disable-next-line*/", "/*eslint no-undef: off */", ` function foo() { @@ -76,6 +80,19 @@ var foo = 1 `, options: [{ allowWholeFile: true }], }, + // -- description + ...(semver.satisfies(eslintVersion, ">=7.0.0 || <6.0.0") + ? [ + ` +/*eslint-disable no-undef -- description*/ +/*eslint-enable no-undef*/ +`, + ` +/*eslint-disable no-undef,no-unused-vars -- description*/ +/*eslint-enable no-undef,no-unused-vars*/ +`, + ] + : []), ], invalid: [ { @@ -193,5 +210,28 @@ console.log(); }, ], }, + // -- description + ...(semver.satisfies(eslintVersion, ">=7.0.0 || <6.0.0") + ? [ + { + code: ` +{ +/*eslint-disable no-unused-vars -- description */ +} +`, + options: [{ allowWholeFile: true }], + errors: [ + { + message: + "Requires 'eslint-enable' directive for 'no-unused-vars'.", + line: 3, + column: 18, + endLine: 3, + endColumn: 32, + }, + ], + }, + ] + : []), ], }) diff --git a/tests/lib/rules/no-aggregating-enable.js b/tests/lib/rules/no-aggregating-enable.js index 46abb1d..4794359 100644 --- a/tests/lib/rules/no-aggregating-enable.js +++ b/tests/lib/rules/no-aggregating-enable.js @@ -4,6 +4,8 @@ */ "use strict" +const semver = require("semver") +const eslintVersion = require("eslint/package").version const RuleTester = require("eslint").RuleTester const rule = require("../../../lib/rules/no-aggregating-enable") const tester = new RuleTester() @@ -64,5 +66,20 @@ tester.run("no-aggregating-enable", rule, { "This `eslint-enable` comment affects 2 `eslint-disable` comments. An `eslint-enable` comment should be for an `eslint-disable` comment.", ], }, + // -- description + ...(semver.satisfies(eslintVersion, ">=7.0.0 || <6.0.0") + ? [ + { + code: ` + /*eslint-disable no-redeclare*/ + /*eslint-disable no-shadow*/ + /*eslint-enable -- description*/ + `, + errors: [ + "This `eslint-enable` comment affects 2 `eslint-disable` comments. An `eslint-enable` comment should be for an `eslint-disable` comment.", + ], + }, + ] + : []), ], }) diff --git a/tests/lib/rules/no-duplicate-disable.js b/tests/lib/rules/no-duplicate-disable.js index e32d877..5b19f5e 100644 --- a/tests/lib/rules/no-duplicate-disable.js +++ b/tests/lib/rules/no-duplicate-disable.js @@ -4,6 +4,8 @@ */ "use strict" +const semver = require("semver") +const eslintVersion = require("eslint/package").version const RuleTester = require("eslint").RuleTester const rule = require("../../../lib/rules/no-duplicate-disable") const tester = new RuleTester() @@ -12,12 +14,21 @@ tester.run("no-duplicate-disable", rule, { valid: [ ` //eslint-disable-line +`, + ` +/*eslint-disable-line*/ `, ` /*eslint-disable no-undef*/ //eslint-disable-line no-unused-vars //eslint-disable-next-line semi /*eslint-disable eqeqeq*/ +`, + ` +/*eslint-disable no-undef*/ +/*eslint-disable-line no-unused-vars*/ +/*eslint-disable-next-line semi*/ +/*eslint-disable eqeqeq*/ `, ], invalid: [ @@ -39,7 +50,37 @@ tester.run("no-duplicate-disable", rule, { { code: ` /*eslint-disable no-undef*/ +/*eslint-disable-line no-undef*/ +`, + errors: [ + { + message: "'no-undef' rule has been disabled already.", + line: 3, + column: 23, + endLine: 3, + endColumn: 31, + }, + ], + }, + { + code: ` +/*eslint-disable no-undef*/ //eslint-disable-next-line no-undef +`, + errors: [ + { + message: "'no-undef' rule has been disabled already.", + line: 3, + column: 28, + endLine: 3, + endColumn: 36, + }, + ], + }, + { + code: ` +/*eslint-disable no-undef*/ +/*eslint-disable-next-line no-undef*/ `, errors: [ { @@ -66,5 +107,41 @@ tester.run("no-duplicate-disable", rule, { }, ], }, + { + code: ` +/*eslint-disable-next-line no-undef*/ +/*eslint-disable-line no-undef*/ +`, + errors: [ + { + message: "'no-undef' rule has been disabled already.", + line: 3, + column: 23, + endLine: 3, + endColumn: 31, + }, + ], + }, + // -- description + ...(semver.satisfies(eslintVersion, ">=7.0.0 || <6.0.0") + ? [ + { + code: ` +// eslint-disable-next-line no-undef -- description +// eslint-disable-line no-undef -- description +`, + errors: [ + { + message: + "'no-undef' rule has been disabled already.", + line: 3, + column: 24, + endLine: 3, + endColumn: 32, + }, + ], + }, + ] + : []), ], }) diff --git a/tests/lib/rules/no-restricted-disable.js b/tests/lib/rules/no-restricted-disable.js index 89f7ff5..bee1641 100644 --- a/tests/lib/rules/no-restricted-disable.js +++ b/tests/lib/rules/no-restricted-disable.js @@ -4,6 +4,8 @@ */ "use strict" +const semver = require("semver") +const eslintVersion = require("eslint/package").version const { Linter, RuleTester } = require("eslint") const rule = require("../../../lib/rules/no-restricted-disable") const coreRules = new Linter().getRules() @@ -17,6 +19,8 @@ tester.run("no-restricted-disable", rule, { "/*eslint-disable*/", "//eslint-disable-line", "//eslint-disable-next-line", + "/*eslint-disable-line*/", + "/*eslint-disable-next-line*/", { code: "/*eslint-disable eqeqeq*/", options: ["no-unused-vars"], @@ -46,21 +50,41 @@ tester.run("no-restricted-disable", rule, { options: ["eqeqeq"], errors: ["Disabling 'eqeqeq' is not allowed."], }, + { + code: "/*eslint-disable-line eqeqeq*/", + options: ["eqeqeq"], + errors: ["Disabling 'eqeqeq' is not allowed."], + }, { code: "//eslint-disable-line", options: ["eqeqeq"], errors: ["Disabling 'eqeqeq' is not allowed."], }, + { + code: "/*eslint-disable-line*/", + options: ["eqeqeq"], + errors: ["Disabling 'eqeqeq' is not allowed."], + }, { code: "//eslint-disable-next-line eqeqeq", options: ["eqeqeq"], errors: ["Disabling 'eqeqeq' is not allowed."], }, + { + code: "/*eslint-disable-next-line eqeqeq*/", + options: ["eqeqeq"], + errors: ["Disabling 'eqeqeq' is not allowed."], + }, { code: "//eslint-disable-next-line", options: ["eqeqeq"], errors: ["Disabling 'eqeqeq' is not allowed."], }, + { + code: "/*eslint-disable-next-line*/", + options: ["eqeqeq"], + errors: ["Disabling 'eqeqeq' is not allowed."], + }, { code: "/*eslint-disable eqeqeq, no-undef, no-redeclare*/", @@ -77,21 +101,41 @@ tester.run("no-restricted-disable", rule, { options: ["*", "!no-undef", "!no-redeclare"], errors: ["Disabling 'eqeqeq' is not allowed."], }, + { + code: "/*eslint-disable-line eqeqeq, no-undef, no-redeclare*/", + options: ["*", "!no-undef", "!no-redeclare"], + errors: ["Disabling 'eqeqeq' is not allowed."], + }, { code: "//eslint-disable-line", options: ["*", "!no-undef", "!no-redeclare"], errors: ["Disabling '*,!no-undef,!no-redeclare' is not allowed."], }, + { + code: "/*eslint-disable-line*/", + options: ["*", "!no-undef", "!no-redeclare"], + errors: ["Disabling '*,!no-undef,!no-redeclare' is not allowed."], + }, { code: "//eslint-disable-next-line eqeqeq, no-undef, no-redeclare", options: ["*", "!no-undef", "!no-redeclare"], errors: ["Disabling 'eqeqeq' is not allowed."], }, + { + code: "/*eslint-disable-next-line eqeqeq, no-undef, no-redeclare*/", + options: ["*", "!no-undef", "!no-redeclare"], + errors: ["Disabling 'eqeqeq' is not allowed."], + }, { code: "//eslint-disable-next-line", options: ["*", "!no-undef", "!no-redeclare"], errors: ["Disabling '*,!no-undef,!no-redeclare' is not allowed."], }, + { + code: "/*eslint-disable-next-line*/", + options: ["*", "!no-undef", "!no-redeclare"], + errors: ["Disabling '*,!no-undef,!no-redeclare' is not allowed."], + }, { code: @@ -112,5 +156,15 @@ tester.run("no-restricted-disable", rule, { "Disabling 'foo/no-redeclare' is not allowed.", ], }, + // -- description + ...(semver.satisfies(eslintVersion, ">=7.0.0 || <6.0.0") + ? [ + { + code: "/*eslint-disable -- description*/", + options: ["eqeqeq"], + errors: ["Disabling 'eqeqeq' is not allowed."], + }, + ] + : []), ], }) diff --git a/tests/lib/rules/no-unlimited-disable.js b/tests/lib/rules/no-unlimited-disable.js index 8622eb8..ade133d 100644 --- a/tests/lib/rules/no-unlimited-disable.js +++ b/tests/lib/rules/no-unlimited-disable.js @@ -4,6 +4,8 @@ */ "use strict" +const semver = require("semver") +const eslintVersion = require("eslint/package").version const RuleTester = require("eslint").RuleTester const rule = require("../../../lib/rules/no-unlimited-disable") const tester = new RuleTester() @@ -14,7 +16,10 @@ tester.run("no-unlimited-disable", rule, { "/*eslint-disable eqeqeq*/", "//eslint-disable-line eqeqeq", "//eslint-disable-next-line eqeqeq", + "/*eslint-disable-line eqeqeq*/", + "/*eslint-disable-next-line eqeqeq*/", "var foo;\n//eslint-disable-line eqeqeq", + "var foo;\n/*eslint-disable-line eqeqeq*/", ], invalid: [ { @@ -35,29 +40,70 @@ tester.run("no-unlimited-disable", rule, { "Unexpected unlimited 'eslint-disable-line' comment. Specify some rule names to disable.", ], }, + { + code: "/*eslint-disable-line*/", + errors: [ + "Unexpected unlimited 'eslint-disable-line' comment. Specify some rule names to disable.", + ], + }, { code: "// eslint-disable-line ", errors: [ "Unexpected unlimited 'eslint-disable-line' comment. Specify some rule names to disable.", ], }, + { + code: "/* eslint-disable-line */", + errors: [ + "Unexpected unlimited 'eslint-disable-line' comment. Specify some rule names to disable.", + ], + }, { code: "//eslint-disable-next-line", errors: [ "Unexpected unlimited 'eslint-disable-next-line' comment. Specify some rule names to disable.", ], }, + { + code: "/*eslint-disable-next-line*/", + errors: [ + "Unexpected unlimited 'eslint-disable-next-line' comment. Specify some rule names to disable.", + ], + }, { code: "// eslint-disable-next-line ", errors: [ "Unexpected unlimited 'eslint-disable-next-line' comment. Specify some rule names to disable.", ], }, + { + code: "/* eslint-disable-next-line */", + errors: [ + "Unexpected unlimited 'eslint-disable-next-line' comment. Specify some rule names to disable.", + ], + }, { code: "var foo;\n//eslint-disable-line", errors: [ "Unexpected unlimited 'eslint-disable-line' comment. Specify some rule names to disable.", ], }, + { + code: "var foo;\n/*eslint-disable-line*/", + errors: [ + "Unexpected unlimited 'eslint-disable-line' comment. Specify some rule names to disable.", + ], + }, + // -- description + ...(semver.satisfies(eslintVersion, ">=7.0.0 || <6.0.0") + ? [ + { + code: "/*eslint-disable -- description */", + errors: [ + "Unexpected unlimited 'eslint-disable' comment. Specify some rule names to disable.", + ], + }, + ] + : []), ], }) diff --git a/tests/lib/rules/no-unused-disable.js b/tests/lib/rules/no-unused-disable.js index e43ed9f..59eb0be 100644 --- a/tests/lib/rules/no-unused-disable.js +++ b/tests/lib/rules/no-unused-disable.js @@ -19,6 +19,8 @@ const fs = require("fs") const path = require("path") const spawn = require("cross-spawn") const rimraf = require("rimraf") +const semver = require("semver") +const eslintVersion = require("eslint/package").version /** * Run eslint CLI command with a given source code. @@ -89,17 +91,32 @@ describe("no-unused-disable", () => { `/*eslint no-undef:error*/ var a = b //eslint-disable-line`, `/*eslint no-undef:error*/ +var a = b /*eslint-disable-line*/`, + `/*eslint no-undef:error*/ var a = b //eslint-disable-line no-undef`, + `/*eslint no-undef:error*/ +var a = b /*eslint-disable-line no-undef*/`, `/*eslint no-undef:error, no-unused-vars:error*/ var a = b //eslint-disable-line no-undef,no-unused-vars`, + `/*eslint no-undef:error, no-unused-vars:error*/ +var a = b /*eslint-disable-line no-undef,no-unused-vars*/`, `/*eslint no-undef:error*/ //eslint-disable-next-line +var a = b`, + `/*eslint no-undef:error*/ +/*eslint-disable-next-line*/ var a = b`, `/*eslint no-undef:error*/ //eslint-disable-next-line no-undef +var a = b`, + `/*eslint no-undef:error*/ +/*eslint-disable-next-line no-undef*/ var a = b`, `/*eslint no-undef:error, no-unused-vars:error*/ //eslint-disable-next-line no-undef,no-unused-vars +var a = b`, + `/*eslint no-undef:error, no-unused-vars:error*/ +/*eslint-disable-next-line no-undef,no-unused-vars*/ var a = b`, `/*eslint no-undef:error*/ /*eslint-disable*/ @@ -133,6 +150,23 @@ function baz() { var foo = 3 //eslint-disable-line no-shadow } `, + ` +/*eslint no-shadow:error */ +var foo = 1 +function bar() { +var foo = 2 /*eslint-disable-line no-shadow*/ +} +function baz() { +var foo = 3 /*eslint-disable-line no-shadow*/ +} +`, + // -- description + ...(semver.satisfies(eslintVersion, ">=7.0.0") + ? [ + `/*eslint no-undef:error*/ +var a = b //eslint-disable-line -- description`, + ] + : []), ]) { it(code, () => runESLint(code).then(messages => { @@ -169,6 +203,20 @@ var a = b //eslint-disable-line`, }, { code: `/*eslint no-undef:off*/ +var a = b /*eslint-disable-line*/`, + errors: [ + { + message: + "ESLint rules are disabled but never reported.", + line: 2, + column: 11, + endLine: 2, + endColumn: 34, + }, + ], + }, + { + code: `/*eslint no-undef:off*/ var a = b //eslint-disable-line no-undef`, errors: [ { @@ -190,6 +238,20 @@ var a = b //eslint-disable-line no-undef`, }, ], }, + { + code: `/*eslint no-undef:off*/ +var a = b /*eslint-disable-line no-undef*/`, + errors: [ + { + message: + "'no-undef' rule is disabled but never reported.", + line: 2, + column: 33, + endLine: 2, + endColumn: 41, + }, + ], + }, { code: `/*eslint no-undef:off, no-unused-vars:off*/ var a = b //eslint-disable-line no-undef,no-unused-vars`, @@ -214,6 +276,28 @@ var a = b //eslint-disable-line no-undef,no-unused-vars`, }, ], }, + { + code: `/*eslint no-undef:off, no-unused-vars:off*/ +var a = b /*eslint-disable-line no-undef,no-unused-vars*/`, + errors: [ + { + message: + "'no-undef' rule is disabled but never reported.", + line: 2, + column: 33, + endLine: 2, + endColumn: 41, + }, + { + message: + "'no-unused-vars' rule is disabled but never reported.", + line: 2, + column: 42, + endLine: 2, + endColumn: 56, + }, + ], + }, { code: `/*eslint no-undef:off*/ //eslint-disable-next-line @@ -240,6 +324,21 @@ var a = b`, }, { code: `/*eslint no-undef:off*/ +/*eslint-disable-next-line*/ +var a = b`, + errors: [ + { + message: + "ESLint rules are disabled but never reported.", + line: 2, + column: 1, + endLine: 2, + endColumn: 29, + }, + ], + }, + { + code: `/*eslint no-undef:off*/ //eslint-disable-next-line no-undef var a = b`, errors: [ @@ -262,6 +361,21 @@ var a = b`, }, ], }, + { + code: `/*eslint no-undef:off*/ +/*eslint-disable-next-line no-undef*/ +var a = b`, + errors: [ + { + message: + "'no-undef' rule is disabled but never reported.", + line: 2, + column: 28, + endLine: 2, + endColumn: 36, + }, + ], + }, { code: `/*eslint no-undef:off, no-unused-vars:off*/ //eslint-disable-next-line no-undef,no-unused-vars @@ -287,6 +401,29 @@ var a = b`, }, ], }, + { + code: `/*eslint no-undef:off, no-unused-vars:off*/ +/*eslint-disable-next-line no-undef,no-unused-vars*/ +var a = b`, + errors: [ + { + message: + "'no-undef' rule is disabled but never reported.", + line: 2, + column: 28, + endLine: 2, + endColumn: 36, + }, + { + message: + "'no-unused-vars' rule is disabled but never reported.", + line: 2, + column: 37, + endLine: 2, + endColumn: 51, + }, + ], + }, { code: `/*eslint no-undef:off*/ /*eslint-disable*/ @@ -463,6 +600,22 @@ var a = b//eslint-disable-line no-undef`, }, { code: `/*eslint no-undef:error*/ +/*eslint-disable*/ +/*eslint-enable*/ +var a = b/*eslint-disable-line no-undef*/`, + errors: [ + { + message: + "ESLint rules are disabled but never reported.", + line: 2, + column: 1, + endLine: 2, + endColumn: 19, + }, + ], + }, + { + code: `/*eslint no-undef:error*/ /*eslint-disable no-undef*/ /*eslint-enable no-undef*/ var a = b//eslint-disable-line no-undef`, @@ -486,6 +639,22 @@ var a = b//eslint-disable-line no-undef`, }, ], }, + { + code: `/*eslint no-undef:error*/ +/*eslint-disable no-undef*/ +/*eslint-enable no-undef*/ +var a = b/*eslint-disable-line no-undef*/`, + errors: [ + { + message: + "'no-undef' rule is disabled but never reported.", + line: 2, + column: 18, + endLine: 2, + endColumn: 26, + }, + ], + }, { code: `/*eslint no-undef:error, no-unused-vars:error*/ /*eslint-disable no-undef,no-unused-vars*/ @@ -505,6 +674,22 @@ var a = b//eslint-disable-line no-undef`, }, { code: `/*eslint no-undef:error, no-unused-vars:error*/ +/*eslint-disable no-undef,no-unused-vars*/ +/*eslint-enable no-undef*/ +var a = b/*eslint-disable-line no-undef*/`, + errors: [ + { + message: + "'no-undef' rule is disabled but never reported.", + line: 2, + column: 18, + endLine: 2, + endColumn: 26, + }, + ], + }, + { + code: `/*eslint no-undef:error, no-unused-vars:error*/ /*eslint-disable no-undef, no-unused-vars, @@ -577,6 +762,25 @@ var a = b //eslint-disable-line`, }, { code: `/*eslint no-undef:off*/ +var a = b /*eslint-disable-line*/`, + errors: [ + { + message: + "Unused eslint-disable directive (no problems were reported).", + }, + { + message: + "ESLint rules are disabled but never reported.", + line: 2, + column: 11, + endLine: 2, + endColumn: 34, + }, + ], + reportUnusedDisableDirectives: true, + }, + { + code: `/*eslint no-undef:off*/ var a = b //eslint-disable-line no-undef`, errors: [ { @@ -603,6 +807,44 @@ var a = b //eslint-disable-line no-undef`, ], reportUnusedDisableDirectives: true, }, + { + code: `/*eslint no-undef:off*/ +var a = b /*eslint-disable-line no-undef*/`, + errors: [ + { + message: + "Unused eslint-disable directive (no problems were reported from 'no-undef').", + }, + { + message: + "'no-undef' rule is disabled but never reported.", + line: 2, + column: 33, + endLine: 2, + endColumn: 41, + }, + ], + reportUnusedDisableDirectives: true, + }, + // -- description + ...(semver.satisfies(eslintVersion, ">=7.0.0") + ? [ + { + code: `/*eslint no-undef:off*/ +var a = b //eslint-disable-line -- description`, + errors: [ + { + message: + "ESLint rules are disabled but never reported.", + line: 2, + column: 11, + endLine: 2, + endColumn: 47, + }, + ], + }, + ] + : []), // Don't crash even if the source code has a parse error. { diff --git a/tests/lib/rules/no-unused-enable.js b/tests/lib/rules/no-unused-enable.js index 60118cc..0430f5c 100644 --- a/tests/lib/rules/no-unused-enable.js +++ b/tests/lib/rules/no-unused-enable.js @@ -4,6 +4,8 @@ */ "use strict" +const semver = require("semver") +const eslintVersion = require("eslint/package").version const RuleTester = require("eslint").RuleTester const rule = require("../../../lib/rules/no-unused-enable") const tester = new RuleTester() @@ -84,5 +86,23 @@ var a = b }, ], }, + // -- description + ...(semver.satisfies(eslintVersion, ">=7.0.0 || <6.0.0") + ? [ + { + code: "/*eslint-enable -- description*/", + errors: [ + { + message: + "ESLint rules are re-enabled but those have not been disabled.", + line: 1, + column: 0, + endLine: 1, + endColumn: 33, + }, + ], + }, + ] + : []), ], }) diff --git a/tests/lib/rules/no-use.js b/tests/lib/rules/no-use.js index 9afa4b3..f94d5c3 100644 --- a/tests/lib/rules/no-use.js +++ b/tests/lib/rules/no-use.js @@ -17,8 +17,6 @@ tester.run("no-use", rule, { "// global", "// globals", "// eslint-env", - "/* eslint-disable-line */", - "/* eslint-disable-next-line */", "/* just eslint in a normal comment */", { code: "/* eslint */", @@ -44,6 +42,14 @@ tester.run("no-use", rule, { code: "// eslint-disable-next-line", options: [{ allow: ["eslint-disable-next-line"] }], }, + { + code: "/* eslint-disable-line */", + options: [{ allow: ["eslint-disable-line"] }], + }, + { + code: "/* eslint-disable-next-line */", + options: [{ allow: ["eslint-disable-next-line"] }], + }, { code: "/* exported */", options: [{ allow: ["exported"] }], @@ -82,6 +88,14 @@ tester.run("no-use", rule, { code: "// eslint-disable-next-line", errors: ["Unexpected ESLint directive comment."], }, + { + code: "/* eslint-disable-line */", + errors: ["Unexpected ESLint directive comment."], + }, + { + code: "/* eslint-disable-next-line */", + errors: ["Unexpected ESLint directive comment."], + }, { code: "/* exported */", errors: ["Unexpected ESLint directive comment."],