diff --git a/docs/src/integrate/nodejs-api.md b/docs/src/integrate/nodejs-api.md index 5560a8080a0..744f98295f4 100644 --- a/docs/src/integrate/nodejs-api.md +++ b/docs/src/integrate/nodejs-api.md @@ -152,7 +152,7 @@ The `ESLint` constructor takes an `options` object. If you omit the `options` ob * `options.plugins` (`Record | null`)
Default is `null`. The plugin implementations that ESLint uses for the `plugins` setting of your configuration. This is a map-like object. Those keys are plugin IDs and each value is implementation. * `options.reportUnusedDisableDirectives` (`"error" | "warn" | "off" | null`)
- Default is `null`. The severity to report unused eslint-disable directives. If this option is a severity, it overrides the `reportUnusedDisableDirectives` setting in your configurations. + Default is `null`. The severity to report unused eslint-disable and eslint-enable directives. If this option is a severity, it overrides the `reportUnusedDisableDirectives` setting in your configurations. * `options.resolvePluginsRelativeTo` (`string` | `null`)
Default is `null`. The path to a directory where plugins should be resolved from. If `null` is present, ESLint loads plugins from the location of the configuration file that contains the plugin setting. If a path is present, ESLint loads all plugins from there. * `options.rulePaths` (`string[]`)
@@ -537,7 +537,7 @@ The most important method on `Linter` is `verify()`, which initiates linting of * `filterCodeBlock` - (optional) A function that decides which code blocks the linter should adopt. The function receives two arguments. The first argument is the virtual filename of a code block. The second argument is the text of the code block. If the function returned `true` then the linter adopts the code block. If the function was omitted, the linter adopts only `*.js` code blocks. If you provided a `filterCodeBlock` function, it overrides this default behavior, so the linter doesn't adopt `*.js` code blocks automatically. * `disableFixes` - (optional) when set to `true`, the linter doesn't make either the `fix` or `suggestions` property of the lint result. * `allowInlineConfig` - (optional) set to `false` to disable inline comments from changing ESLint rules. - * `reportUnusedDisableDirectives` - (optional) when set to `true`, adds reported errors for unused `eslint-disable` directives when no problems would be reported in the disabled area anyway. + * `reportUnusedDisableDirectives` - (optional) when set to `true`, adds reported errors for unused `eslint-disable` and `eslint-enable` directives when no problems would be reported in the disabled area anyway. If the third argument is a string, it is interpreted as the `filename`. diff --git a/docs/src/use/command-line-interface.md b/docs/src/use/command-line-interface.md index da4faf70eba..6087aae4fcc 100644 --- a/docs/src/use/command-line-interface.md +++ b/docs/src/use/command-line-interface.md @@ -97,7 +97,7 @@ Output: Inline configuration comments: --no-inline-config Prevent comments from changing config or rules - --report-unused-disable-directives Adds reported errors for unused eslint-disable directives + --report-unused-disable-directives Adds reported errors for unused eslint-disable and eslint-enable directives Caching: --cache Only check changed files - default: false @@ -577,7 +577,7 @@ This option causes ESLint to report directive comments like `// eslint-disable-l * **Argument Type**: No argument. -This can be useful to prevent future errors from unexpectedly being suppressed, by cleaning up old `eslint-disable` comments which are no longer applicable. +This can be useful to prevent future errors from unexpectedly being suppressed, by cleaning up old `eslint-disable` and `eslint-enable` comments which are no longer applicable. ::: warning When using this option, it is possible that new errors start being reported whenever ESLint or custom rules are upgraded. diff --git a/docs/src/use/configure/configuration-files-new.md b/docs/src/use/configure/configuration-files-new.md index 2d472a4e7e1..d3ba4cd2bcf 100644 --- a/docs/src/use/configure/configuration-files-new.md +++ b/docs/src/use/configure/configuration-files-new.md @@ -76,7 +76,7 @@ Each configuration object contains all of the information ESLint needs to execut * `parserOptions` - An object specifying additional options that are passed directly to the `parse()` or `parseForESLint()` method on the parser. The available options are parser-dependent. * `linterOptions` - An object containing settings related to the linting process. * `noInlineConfig` - A Boolean value indicating if inline configuration is allowed. - * `reportUnusedDisableDirectives` - A Boolean value indicating if unused disable directives should be tracked and reported. + * `reportUnusedDisableDirectives` - A Boolean value indicating if unused disable and enable directives should be tracked and reported. * `processor` - Either an object containing `preprocess()` and `postprocess()` methods or a string indicating the name of a processor inside of a plugin (i.e., `"pluginName/processorName"`). * `plugins` - An object containing a name-value mapping of plugin names to plugin objects. When `files` is specified, these plugins are only available to the matching files. * `rules` - An object containing the configured rules. When `files` or `ignores` are specified, these rule configurations are only available to the matching files. @@ -244,7 +244,7 @@ export default [ #### Reporting unused disable directives -Disable directives such as `/*eslint-disable*/` and `/*eslint-disable-next-line*/` are used to disable ESLint rules around certain portions of code. As code changes, it's possible for these directives to no longer be needed because the code has changed in such a way that the rule is no longer triggered. You can enable reporting of these unused disable directives by setting the `reportUnusedDisableDirectives` option to `true`, as in this example: +Disable and enable directives such as `/*eslint-disable*/`, `/*eslint-enable*/` and `/*eslint-disable-next-line*/` are used to disable ESLint rules around certain portions of code. As code changes, it's possible for these directives to no longer be needed because the code has changed in such a way that the rule is no longer triggered. You can enable reporting of these unused disable directives by setting the `reportUnusedDisableDirectives` option to `true`, as in this example: ```js export default [ @@ -257,7 +257,7 @@ export default [ ]; ``` -By default, unused disable directives are reported as warnings. You can change this setting using the `--report-unused-disable-directives` command line option. +By default, unused disable and enable directives are reported as warnings. You can change this setting using the `--report-unused-disable-directives` command line option. ### Configuring language options diff --git a/lib/linter/apply-disable-directives.js b/lib/linter/apply-disable-directives.js index 55f7683f3f5..c5e3c9ddc1c 100644 --- a/lib/linter/apply-disable-directives.js +++ b/lib/linter/apply-disable-directives.js @@ -30,7 +30,7 @@ function compareLocations(itemA, itemB) { /** * Groups a set of directives into sub-arrays by their parent comment. - * @param {Directive[]} directives Unused directives to be removed. + * @param {Iterable} directives Unused directives to be removed. * @returns {Directive[][]} Directives grouped by their parent comment. */ function groupByParentComment(directives) { @@ -177,10 +177,10 @@ function createCommentRemoval(directives, commentToken) { /** * Parses details from directives to create output Problems. - * @param {Directive[]} allDirectives Unused directives to be removed. + * @param {Iterable} allDirectives Unused directives to be removed. * @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems. */ -function processUnusedDisableDirectives(allDirectives) { +function processUnusedDirectives(allDirectives) { const directiveGroups = groupByParentComment(allDirectives); return directiveGroups.flatMap( @@ -199,6 +199,95 @@ function processUnusedDisableDirectives(allDirectives) { ); } +/** + * Collect eslint-enable comments that are removing suppressions by eslint-disable comments. + * @param {Directive[]} directives The directives to check. + * @returns {Set} The used eslint-enable comments + */ +function collectUsedEnableDirectives(directives) { + + /** + * A Map of `eslint-enable` keyed by ruleIds that may be marked as used. + * If `eslint-enable` does not have a ruleId, the key will be `null`. + * @type {Map} + */ + const enabledRules = new Map(); + + /** + * A Set of `eslint-enable` marked as used. + * It is also the return value of `collectUsedEnableDirectives` function. + * @type {Set} + */ + const usedEnableDirectives = new Set(); + + /* + * Checks the directives backwards to see if the encountered `eslint-enable` is used by the previous `eslint-disable`, + * and if so, stores the `eslint-enable` in `usedEnableDirectives`. + */ + for (let index = directives.length - 1; index >= 0; index--) { + const directive = directives[index]; + + if (directive.type === "disable") { + if (enabledRules.size === 0) { + continue; + } + if (directive.ruleId === null) { + + // If encounter `eslint-disable` without ruleId, + // mark all `eslint-enable` currently held in enabledRules as used. + // e.g. + // /* eslint-disable */ <- current directive + // /* eslint-enable rule-id1 */ <- used + // /* eslint-enable rule-id2 */ <- used + // /* eslint-enable */ <- used + for (const enableDirective of enabledRules.values()) { + usedEnableDirectives.add(enableDirective); + } + enabledRules.clear(); + } else { + const enableDirective = enabledRules.get(directive.ruleId); + + if (enableDirective) { + + // If encounter `eslint-disable` with ruleId, and there is an `eslint-enable` with the same ruleId in enabledRules, + // mark `eslint-enable` with ruleId as used. + // e.g. + // /* eslint-disable rule-id */ <- current directive + // /* eslint-enable rule-id */ <- used + usedEnableDirectives.add(enableDirective); + } else { + const enabledDirectiveWithoutRuleId = enabledRules.get(null); + + if (enabledDirectiveWithoutRuleId) { + + // If encounter `eslint-disable` with ruleId, and there is no `eslint-enable` with the same ruleId in enabledRules, + // mark `eslint-enable` without ruleId as used. + // e.g. + // /* eslint-disable rule-id */ <- current directive + // /* eslint-enable */ <- used + usedEnableDirectives.add(enabledDirectiveWithoutRuleId); + } + } + } + } else if (directive.type === "enable") { + if (directive.ruleId === null) { + + // If encounter `eslint-enable` without ruleId, the `eslint-enable` that follows it are unused. + // So clear enabledRules. + // e.g. + // /* eslint-enable */ <- current directive + // /* eslint-enable rule-id *// <- unused + // /* eslint-enable */ <- unused + enabledRules.clear(); + enabledRules.set(null, directive); + } else { + enabledRules.set(directive.ruleId, directive); + } + } + } + return usedEnableDirectives; +} + /** * This is the same as the exported function, except that it * doesn't handle disable-line and disable-next-line directives, and it always reports unused @@ -206,7 +295,7 @@ 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: LintMessage[], unusedDisableDirectives: LintMessage[]}} An object with a list + * @returns {{problems: LintMessage[], unusedDirectives: LintMessage[]}} An object with a list * of problems (including suppressed ones) and unused eslint-disable directives */ function applyDirectives(options) { @@ -258,17 +347,42 @@ function applyDirectives(options) { const unusedDisableDirectivesToReport = options.directives .filter(directive => directive.type === "disable" && !usedDisableDirectives.has(directive)); - const processed = processUnusedDisableDirectives(unusedDisableDirectivesToReport); - const unusedDisableDirectives = processed + const unusedEnableDirectivesToReport = new Set( + options.directives.filter(directive => directive.unprocessedDirective.type === "enable") + ); + + /* + * If directives has the eslint-enable directive, + * check whether the eslint-enable comment is used. + */ + if (unusedEnableDirectivesToReport.size > 0) { + for (const directive of collectUsedEnableDirectives(options.directives)) { + unusedEnableDirectivesToReport.delete(directive); + } + } + + const processed = processUnusedDirectives(unusedDisableDirectivesToReport) + .concat(processUnusedDirectives(unusedEnableDirectivesToReport)); + + const unusedDirectives = processed .map(({ description, fix, unprocessedDirective }) => { const { parentComment, type, line, column } = unprocessedDirective; + let message; + + if (type === "enable") { + message = description + ? `Unused eslint-enable directive (no matching eslint-disable directives were found for ${description}).` + : "Unused eslint-enable directive (no matching eslint-disable directives were found)."; + } else { + message = description + ? `Unused eslint-disable directive (no problems were reported from ${description}).` + : "Unused eslint-disable directive (no problems were reported)."; + } return { ruleId: null, - message: description - ? `Unused eslint-disable directive (no problems were reported from ${description}).` - : "Unused eslint-disable directive (no problems were reported).", + message, 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, @@ -277,7 +391,7 @@ function applyDirectives(options) { }; }); - return { problems, unusedDisableDirectives }; + return { problems, unusedDirectives }; } /** @@ -344,8 +458,8 @@ module.exports = ({ directives, disableFixes, problems, reportUnusedDisableDirec return reportUnusedDisableDirectives !== "off" ? lineDirectivesResult.problems - .concat(blockDirectivesResult.unusedDisableDirectives) - .concat(lineDirectivesResult.unusedDisableDirectives) + .concat(blockDirectivesResult.unusedDirectives) + .concat(lineDirectivesResult.unusedDirectives) .sort(compareLocations) : lineDirectivesResult.problems; }; diff --git a/lib/options.js b/lib/options.js index ae9a5d5552a..81c0fa60ab9 100644 --- a/lib/options.js +++ b/lib/options.js @@ -47,7 +47,7 @@ const optionator = require("optionator"); * @property {Object} [parserOptions] Specify parser options * @property {string[]} [plugin] Specify plugins * @property {string} [printConfig] Print the configuration for the given file - * @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable directives + * @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable and eslint-enable directives * @property {string} [resolvePluginsRelativeTo] A folder where plugins should be resolved from, CWD by default * @property {Object} [rule] Specify rules * @property {string[]} [rulesdir] Load additional rules from this directory. Deprecated: Use rules from plugins @@ -304,7 +304,7 @@ module.exports = function(usingFlatConfig) { option: "report-unused-disable-directives", type: "Boolean", default: void 0, - description: "Adds reported errors for unused eslint-disable directives" + description: "Adds reported errors for unused eslint-disable and eslint-enable directives" }, { heading: "Caching" diff --git a/tests/lib/linter/apply-disable-directives.js b/tests/lib/linter/apply-disable-directives.js index de56f729627..d56bf5bc1b0 100644 --- a/tests/lib/linter/apply-disable-directives.js +++ b/tests/lib/linter/apply-disable-directives.js @@ -680,7 +680,7 @@ describe("apply-disable-directives", () => { applyDisableDirectives({ directives: [ { parentComment: createParentComment([0, 31]), type: "disable-next-line", line: 1, column: 1, ruleId: null, justification: "j1" }, - { type: "enable", line: 1, column: 5, ruleId: null, justification: "j2" } + { parentComment: createParentComment([31, 50]), type: "enable", line: 1, column: 31, ruleId: null, justification: "j2" } ], problems: [{ line: 2, column: 2, ruleId: "foo" }] }), @@ -1365,28 +1365,140 @@ describe("apply-disable-directives", () => { ); }); - it("Adds a problem for // eslint-disable-line", () => { + it("Adds a problem for /* eslint-enable */", () => { assert.deepStrictEqual( applyDisableDirectives({ directives: [{ - parentComment: createParentComment([0, 22]), - type: "disable-line", + parentComment: createParentComment([0, 20]), + type: "enable", line: 1, column: 1, - ruleId: null, justification: "justification" }], problems: [], reportUnusedDisableDirectives: "error" }), + [{ + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 1, + column: 1, + fix: { + range: [0, 20], + text: " " + }, + severity: 2, + nodeType: null + }] + ); + }); + + it("Does not fix a problem for /* eslint-enable */ when disableFixes is enabled", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ + parentComment: createParentComment([0, 20]), + type: "enable", + line: 1, + column: 1, + justification: "justification" + }], + disableFixes: true, + problems: [], + reportUnusedDisableDirectives: "error" + }), + [{ + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 1, + column: 1, + severity: 2, + nodeType: null + }] + ); + }); + + it("Does not add a problem for /* eslint-disable */ /* (problem) */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { type: "disable", line: 1, column: 1, ruleId: null, justification: "justification" }, + { type: "enable", line: 3, column: 1, ruleId: null, justification: "justification" } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [{ line: 2, column: 1, ruleId: "foo", suppressions: [{ kind: "directive", justification: "justification" }] }] + ); + }); + + it("Adds a problem for /* eslint-enable foo */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ + parentComment: createParentComment([0, 21]), + type: "enable", + line: 1, + column: 1, + ruleId: "foo", + justification: "justification" + }], + problems: [], + reportUnusedDisableDirectives: "error" + }), + [{ + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 1, + column: 1, + fix: { + range: [0, 21], + text: " " + }, + severity: 2, + nodeType: null + }] + ); + }); + + it("Adds a problem for /* eslint-disable not-foo */ /* (problem from not-foo) */ /* eslint-enable foo */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 24]), + type: "disable", + line: 1, + column: 1, + ruleId: "not-foo", + justification: "justification" + }, + { + parentComment: createParentComment([48, 72]), + type: "enable", + line: 3, + column: 1, + ruleId: "foo", + justification: "justification" + } + ], + problems: [{ line: 2, column: 1, ruleId: "not-foo" }], + reportUnusedDisableDirectives: "error" + }), [ + { + ruleId: "not-foo", + line: 2, + column: 1, + suppressions: [{ justification: "justification", kind: "directive" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported).", - line: 1, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 3, column: 1, fix: { - range: [0, 22], + range: [48, 72], text: " " }, severity: 2, @@ -1396,40 +1508,1155 @@ describe("apply-disable-directives", () => { ); }); + it("Adds a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable */ /* eslint-enable */ /* eslint-enable foo */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([42, 63]), + type: "enable", + line: 3, + column: 1, + ruleId: null, + justification: "j1" + }, + { + parentComment: createParentComment([63, 84]), + type: "enable", + line: 4, + column: 1, + ruleId: null, + justification: "j1" + }, + { + parentComment: createParentComment([84, 105]), + type: "enable", + line: 5, + column: 1, + ruleId: "foo", + justification: "j2" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: "foo", + line: 2, + column: 1, + suppressions: [{ justification: "j1", kind: "directive" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + fix: { + range: [63, 84], + text: " " + }, + line: 4, + column: 1, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + fix: { + range: [84, 105], + text: " " + }, + line: 5, + column: 1, + severity: 2, + nodeType: null + } + ] + ); + }); - it("Does not add a problem for // eslint-disable-line (problem)", () => { + it("Adds a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable */ /* eslint-enable */", () => { assert.deepStrictEqual( applyDisableDirectives({ - directives: [{ type: "disable-line", line: 1, column: 1, ruleId: null, justification: "justification" }], - problems: [{ line: 1, column: 10, ruleId: "foo" }], + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([42, 63]), + type: "enable", + line: 3, + column: 1, + ruleId: null, + justification: "j1" + }, + { + parentComment: createParentComment([63, 84]), + type: "enable", + line: 4, + column: 1, + ruleId: null, + justification: "j1" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], reportUnusedDisableDirectives: "error" }), - [{ line: 1, column: 10, ruleId: "foo", suppressions: [{ kind: "directive", justification: "justification" }] }] + [ + { + ruleId: "foo", + line: 2, + column: 1, + suppressions: [{ justification: "j1", kind: "directive" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + fix: { + range: [63, 84], + text: " " + }, + line: 4, + column: 1, + severity: 2, + nodeType: null + } + ] ); }); - it("Adds a problem for // eslint-disable-next-line", () => { + it("Adds two problems for /* eslint-enable */ /* eslint-enable */", () => { assert.deepStrictEqual( applyDisableDirectives({ - directives: [{ - parentComment: createParentComment([0, 27]), - type: "disable-next-line", + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "enable", + line: 1, + column: 1, + ruleId: null, + justification: "j1" + }, + { + parentComment: createParentComment([21, 42]), + type: "enable", + line: 2, + column: 1, + ruleId: null, + justification: "j2" + } + ], + problems: [], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", line: 1, - column: 2, + column: 1, + fix: { + range: [0, 21], + text: " " + }, + severity: 2, + nodeType: null + }, + { ruleId: null, - justification: "justification" - }], + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 2, + column: 1, + fix: { + range: [21, 42], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds a problem for /* eslint-enable */ /* eslint-disable */ /* (problem) */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "enable", + line: 1, + column: 1, + ruleId: null, + justification: "j1" + }, + { + parentComment: createParentComment([21, 42]), + type: "disable", + line: 2, + column: 1, + ruleId: null, + justification: "j2" + }, + { + parentComment: createParentComment([63, 84]), + type: "enable", + line: 4, + column: 1, + ruleId: null, + justification: "j3" + } + ], + problems: [{ line: 3, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 1, + column: 1, + fix: { + range: [0, 21], + text: " " + }, + severity: 2, + nodeType: null + }, + { + line: 3, + column: 1, + ruleId: "foo", + suppressions: [{ kind: "directive", justification: "j2" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable */ /* eslint-enable foo */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([42, 63]), + type: "enable", + line: 3, + column: 1, + ruleId: null, + justification: "j2" + }, + { + parentComment: createParentComment([63, 84]), + type: "enable", + line: 4, + column: 1, + ruleId: "foo", + justification: "j3" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + line: 2, + column: 1, + ruleId: "foo", + suppressions: [{ kind: "directive", justification: "j1" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 4, + column: 1, + fix: { + range: [63, 84], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Does not add a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable foo */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { type: "disable", line: 1, column: 1, ruleId: "foo", justification: "j1" }, + { type: "enable", line: 3, column: 1, ruleId: "foo", justification: "j2" } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [{ line: 2, column: 1, ruleId: "foo", suppressions: [{ kind: "directive", justification: "j1" }] }] + ); + }); + + it("Adds a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable foo */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 21]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([42, 63]), + type: "enable", + line: 3, + column: 1, + ruleId: "foo", + justification: "j2" + }, + { + parentComment: createParentComment([63, 84]), + type: "enable", + line: 4, + column: 1, + ruleId: null, + justification: "j3" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + line: 2, + column: 1, + ruleId: "foo", + suppressions: [ + { kind: "directive", justification: "j1" } + ] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 4, + column: 1, + fix: { + range: [63, 84], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable bar */ /* (problem from bar) */ /* eslint-enable foo */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 20]), + type: "disable", + line: 1, + column: 1, + ruleId: "bar", + justification: "j1" + }, + { + parentComment: createParentComment([60, 80]), + type: "enable", + line: 3, + column: 1, + ruleId: "foo", + justification: "j2" + }, + { + parentComment: createParentComment([80, 100]), + type: "enable", + line: 4, + column: 1, + ruleId: null, + justification: "j3" + } + ], + problems: [{ line: 2, column: 1, ruleId: "bar" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + line: 2, + column: 1, + ruleId: "bar", + suppressions: [{ kind: "directive", justification: "j1" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 3, + column: 1, + fix: { + range: [60, 80], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable foo */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 20]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([60, 80]), + type: "enable", + line: 3, + column: 1, + ruleId: "foo", + justification: "j2" + }, + { + parentComment: createParentComment([80, 100]), + type: "enable", + line: 4, + column: 1, + ruleId: "foo", + justification: "j3" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + line: 2, + column: 1, + ruleId: "foo", + suppressions: [{ kind: "directive", justification: "j1" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 4, + column: 1, + fix: { + range: [80, 100], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds two problems for /* eslint-disable foo */ /* (problem from foo) */ /* eslint-enable foo */ /* eslint-enable foo */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 20]), + type: "disable", + line: 1, + column: 1, + ruleId: "foo", + justification: "j1" + }, + { + parentComment: createParentComment([40, 60]), + type: "enable", + line: 3, + column: 1, + ruleId: "foo", + justification: "j2" + }, + { + parentComment: createParentComment([60, 80]), + type: "enable", + line: 4, + column: 1, + ruleId: "foo", + justification: "j3" + }, + { + parentComment: createParentComment([80, 100]), + type: "enable", + line: 5, + column: 1, + ruleId: null, + justification: "j4" + } + ], + problems: [{ line: 2, column: 1, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: "foo", + line: 2, + column: 1, + suppressions: [{ kind: "directive", justification: "j1" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'foo').", + line: 4, + column: 1, + fix: { + range: [60, 80], + text: " " + }, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 5, + column: 1, + fix: { + range: [80, 100], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-disable used */ /* (problem from used) */ /* eslint-enable used */ /* eslint-enable */", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment: createParentComment([0, 20]), + ruleId: "used", + type: "disable", + line: 1, + column: 1, + justification: "j1" + }, + { + parentComment: createParentComment([40, 60]), + ruleId: "used", + type: "disable", + line: 3, + column: 1, + justification: "j2" + }, + { + parentComment: createParentComment([80, 100]), + ruleId: "used", + type: "enable", + line: 5, + column: 1, + justification: "j3" + }, + { + parentComment: createParentComment([100, 120]), + ruleId: null, + type: "enable", + line: 6, + column: 1, + justification: "j4" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }, { line: 4, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, + { + line: 4, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }, { kind: "directive", justification: "j2" }] + }, + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 6, + column: 1, + fix: { + range: [100, 120], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Adds a problem for // eslint-disable-line", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ + parentComment: createParentComment([0, 22]), + type: "disable-line", + line: 1, + column: 1, + ruleId: null, + justification: "justification" + }], + problems: [], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported).", + line: 1, + column: 1, + fix: { + range: [0, 22], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + + it("Does not add a problem for // eslint-disable-line (problem)", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ type: "disable-line", line: 1, column: 1, ruleId: null, justification: "justification" }], + problems: [{ line: 1, column: 10, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [{ line: 1, column: 10, ruleId: "foo", suppressions: [{ kind: "directive", justification: "justification" }] }] + ); + }); + + it("Adds a problem for // eslint-disable-next-line", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ + parentComment: createParentComment([0, 27]), + type: "disable-next-line", + line: 1, + column: 2, + ruleId: null, + justification: "justification" + }], + problems: [], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported).", + line: 1, + column: 2, + fix: { + range: [0, 27], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Does not add a problem for // eslint-disable-next-line \\n (problem)", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ type: "disable-next-line", line: 1, column: 1, ruleId: null, justification: "justification" }], + problems: [{ line: 2, column: 10, ruleId: "foo" }], + reportUnusedDisableDirectives: "error" + }), + [{ line: 2, column: 10, ruleId: "foo", suppressions: [{ kind: "directive", justification: "justification" }] }] + ); + }); + + it("adds two problems for /* eslint-disable */ // eslint-disable-line", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { parentComment: createParentComment([0, 20]), type: "disable", line: 1, column: 1, ruleId: null }, + { parentComment: createParentComment([20, 43]), type: "disable-line", line: 1, column: 22, ruleId: null } + ], + problems: [], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported).", + line: 1, + column: 1, + fix: { + range: [0, 20], + text: " " + }, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported).", + line: 1, + column: 22, + fix: { + range: [20, 43], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + }); + + it("Does not add problems when reportUnusedDisableDirectives: \"off\" is used", () => { + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [{ + parentComment: createParentComment([0, 27]), + type: "disable-next-line", + line: 1, + column: 1, + ruleId: null, + justification: "justification" + }], + problems: [], + reportUnusedDisableDirectives: "off" + }), + [] + ); + }); + }); + + describe("unused rules within directives", () => { + it("Adds a problem for /* eslint-disable used, unused */", () => { + const parentComment = createParentComment([0, 32], " eslint-disable used, unused ", ["used", "unused"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "unused", + type: "disable", + line: 1, + column: 22, + justification: "j2" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused').", + line: 1, + column: 22, + fix: { + range: [22, 30], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + } + ] + ); + }); + it("Adds a problem for /* eslint-disable used , unused , -- unused and used are ok */", () => { + const parentComment = createParentComment([0, 62], " eslint-disable used , unused , -- unused and used are ok ", ["used", "unused"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "unused", + type: "disable", + line: 1, + column: 24, + justification: "j2" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused').", + line: 1, + column: 24, + fix: { + range: [23, 32], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable unused, used */", () => { + const parentComment = createParentComment([0, 32], " eslint-disable unused, used ", ["unused", "used"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "unused", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 25, + justification: "j2" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused').", + line: 1, + column: 18, + fix: { + range: [18, 26], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j2" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable unused,, ,, used */", () => { + const parentComment = createParentComment([0, 37], " eslint-disable unused,, ,, used ", ["unused", "used"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "unused", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 29, + justification: "j2" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused').", + line: 1, + column: 18, + fix: { + range: [18, 25], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j2" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable unused-1, unused-2, used */", () => { + const parentComment = createParentComment([0, 45], " eslint-disable unused-1, unused-2, used ", ["unused-1", "unused-2", "used"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "unused-1", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "unused-2", + type: "disable", + line: 1, + column: 28, + justification: "j2" + }, + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 38, + justification: "j3" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused-1').", + line: 1, + column: 18, + fix: { + range: [18, 28], + text: "" + }, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused-2').", + line: 1, + column: 28, + fix: { + range: [26, 36], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j3" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable unused-1, unused-2, used, unused-3 */", () => { + const parentComment = createParentComment([0, 55], " eslint-disable unused-1, unused-2, used, unused-3 ", ["unused-1", "unused-2", "used", "unused-3"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "unused-1", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "unused-2", + type: "disable", + line: 1, + column: 28, + justification: "j2" + }, + { + parentComment, + ruleId: "used", + type: "disable", + line: 1, + column: 38, + justification: "j3" + }, + { + parentComment, + ruleId: "unused-3", + type: "disable", + line: 1, + column: 43, + justification: "j4" + } + ], + problems: [{ line: 2, column: 1, ruleId: "used" }], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused-1').", + line: 1, + column: 18, + fix: { + range: [18, 28], + text: "" + }, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused-2').", + line: 1, + column: 28, + fix: { + range: [26, 36], + text: "" + }, + severity: 2, + nodeType: null + }, + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'unused-3').", + line: 1, + column: 43, + fix: { + range: [42, 52], + text: "" + }, + severity: 2, + nodeType: null + }, + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j3" }] + } + ] + ); + }); + + it("Adds a problem for /* eslint-disable unused-1, unused-2 */", () => { + const parentComment = createParentComment([0, 39], " eslint-disable unused-1, unused-2 ", ["unused-1", "unused-2"]); + + assert.deepStrictEqual( + applyDisableDirectives({ + directives: [ + { + parentComment, + ruleId: "unused-1", + type: "disable", + line: 1, + column: 18, + justification: "j1" + }, + { + parentComment, + ruleId: "unused-2", + type: "disable", + line: 1, + column: 28, + justification: "j2" + } + ], problems: [], reportUnusedDisableDirectives: "error" }), [ { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported).", + message: "Unused eslint-disable directive (no problems were reported from 'unused-1' or 'unused-2').", line: 1, - column: 2, + column: 18, fix: { - range: [0, 27], + range: [0, 39], text: " " }, severity: 2, @@ -1439,23 +2666,33 @@ describe("apply-disable-directives", () => { ); }); - it("Does not add a problem for // eslint-disable-next-line \\n (problem)", () => { - assert.deepStrictEqual( - applyDisableDirectives({ - directives: [{ type: "disable-next-line", line: 1, column: 1, ruleId: null, justification: "justification" }], - problems: [{ line: 2, column: 10, ruleId: "foo" }], - reportUnusedDisableDirectives: "error" - }), - [{ line: 2, column: 10, ruleId: "foo", suppressions: [{ kind: "directive", justification: "justification" }] }] - ); - }); + it("Adds a problem for /* eslint-disable unused-1, unused-2, unused-3 */", () => { + const parentComment = createParentComment([0, 49], " eslint-disable unused-1, unused-2, unused-3 ", ["unused-1", "unused-2", "unused-3"]); - it("adds two problems for /* eslint-disable */ // eslint-disable-line", () => { assert.deepStrictEqual( applyDisableDirectives({ directives: [ - { parentComment: createParentComment([0, 20]), type: "disable", line: 1, column: 1, ruleId: null }, - { parentComment: createParentComment([20, 43]), type: "disable-line", line: 1, column: 22, ruleId: null } + { + parentComment, + ruleId: "unused-1", + type: "disable", + line: 1, + column: 18 + }, + { + parentComment, + ruleId: "unused-2", + type: "disable", + line: 1, + column: 28 + }, + { + parentComment, + ruleId: "unused-3", + type: "disable", + line: 1, + column: 38 + } ], problems: [], reportUnusedDisableDirectives: "error" @@ -1463,23 +2700,11 @@ describe("apply-disable-directives", () => { [ { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported).", - line: 1, - column: 1, - fix: { - range: [0, 20], - text: " " - }, - severity: 2, - nodeType: null - }, - { - ruleId: null, - message: "Unused eslint-disable directive (no problems were reported).", + message: "Unused eslint-disable directive (no problems were reported from 'unused-1', 'unused-2', or 'unused-3').", line: 1, - column: 22, + column: 18, fix: { - range: [20, 43], + range: [0, 49], text: " " }, severity: 2, @@ -1489,263 +2714,356 @@ describe("apply-disable-directives", () => { ); }); - it("Does not add problems when reportUnusedDisableDirectives: \"off\" is used", () => { + it("Adds a problem for /* eslint-disable foo */ \\n (problem from foo and bar) // eslint-disable-line foo, bar", () => { assert.deepStrictEqual( applyDisableDirectives({ - directives: [{ - parentComment: createParentComment([0, 27]), - type: "disable-next-line", - line: 1, + directives: [ + { + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), + ruleId: "foo", + type: "disable", + line: 1, + column: 1, + justification: "j1" + }, + { + parentComment: createParentComment([41, 81], " eslint-disable-line foo, bar", ["foo", "bar"]), + ruleId: "foo", + type: "disable-line", + line: 2, + column: 11, + justification: "j2" + }, + { + parentComment: createParentComment([41, 81], " eslint-disable-line foo, bar ", ["foo", "bar"]), + ruleId: "bar", + type: "disable-line", + line: 2, + column: 11, + justification: "j2" + } + ], + problems: [ + { line: 2, column: 1, ruleId: "bar" }, + { line: 2, column: 6, ruleId: "foo" } + ], + reportUnusedDisableDirectives: "error" + }), + [ + { + ruleId: "bar", + line: 2, column: 1, + suppressions: [{ kind: "directive", justification: "j2" }] + }, + { + ruleId: "foo", + line: 2, + column: 6, + suppressions: [ + { kind: "directive", justification: "j1" }, + { kind: "directive", justification: "j2" } + ] + }, + { ruleId: null, - justification: "justification" - }], - problems: [], - reportUnusedDisableDirectives: "off" - }), - [] + message: "Unused eslint-disable directive (no problems were reported from 'foo').", + line: 2, + column: 11, + fix: { + range: [64, 69], + text: "" + }, + severity: 2, + nodeType: null + } + ] ); }); - }); - describe("unused rules within directives", () => { - it("Adds a problem for /* eslint-disable used, unused */", () => { - const parentComment = createParentComment([0, 32], " eslint-disable used, unused ", ["used", "unused"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable used, unused */", () => { + const parentComment = createParentComment([0, 32], " eslint-enable used, unused ", ["used", "unused"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "unused", - type: "disable", - line: 1, - column: 22, + ruleId: "used", + type: "enable", + line: 3, + column: 1, justification: "j2" + }, + { + parentComment, + ruleId: "unused", + type: "enable", + line: 4, + column: 1, + justification: "j3" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused').", - line: 1, - column: 22, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused').", + line: 4, + column: 1, fix: { - range: [22, 30], + range: [21, 29], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j1" }] } ] ); }); - it("Adds a problem for /* eslint-disable used , unused , -- unused and used are ok */", () => { - const parentComment = createParentComment([0, 62], " eslint-disable used , unused , -- unused and used are ok ", ["used", "unused"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable used , unused , -- unused and used are ok */", () => { + const parentComment = createParentComment([0, 62], " eslint-enable used , unused , -- unused and used are ok ", ["used", "unused"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "unused", - type: "disable", - line: 1, - column: 24, + ruleId: "used", + type: "enable", + line: 3, + column: 1, justification: "j2" + }, + { + parentComment, + ruleId: "unused", + type: "enable", + line: 4, + column: 1, + justification: "j3" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused').", - line: 1, - column: 24, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused').", + line: 4, + column: 1, fix: { - range: [23, 32], + range: [22, 31], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j1" }] } ] ); }); - it("Adds a problem for /* eslint-disable unused, used */", () => { - const parentComment = createParentComment([0, 32], " eslint-disable unused, used ", ["unused", "used"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable unused, used */", () => { + const parentComment = createParentComment([0, 32], " eslint-enable unused, used ", ["unused", "used"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, - ruleId: "unused", + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), + ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "used", - type: "disable", - line: 1, - column: 25, + ruleId: "unused", + type: "enable", + line: 3, + column: 1, justification: "j2" + }, + { + parentComment, + ruleId: "used", + type: "enable", + line: 4, + column: 1, + justification: "j3" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused').", - line: 1, - column: 18, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused').", + line: 3, + column: 1, fix: { - range: [18, 26], + range: [17, 25], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j2" }] } ] ); }); - it("Adds a problem for /* eslint-disable unused,, ,, used */", () => { - const parentComment = createParentComment([0, 37], " eslint-disable unused,, ,, used ", ["unused", "used"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable unused,, ,, used */", () => { + const parentComment = createParentComment([0, 37], " eslint-enable unused,, ,, used ", ["unused", "used"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, - ruleId: "unused", + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), + ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "used", - type: "disable", - line: 1, - column: 29, + ruleId: "unused", + type: "enable", + line: 3, + column: 1, justification: "j2" + }, + { + parentComment, + ruleId: "used", + type: "enable", + line: 4, + column: 1, + justification: "j3" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused').", - line: 1, - column: 18, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused').", + line: 3, + column: 1, fix: { - range: [18, 25], + range: [17, 24], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j2" }] } ] ); }); - it("Adds a problem for /* eslint-disable unused-1, unused-2, used */", () => { - const parentComment = createParentComment([0, 45], " eslint-disable unused-1, unused-2, used ", ["unused-1", "unused-2", "used"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable unused-1, unused-2, used */", () => { + const parentComment = createParentComment([0, 45], " eslint-enable unused-1, unused-2, used ", ["unused-1", "unused-2", "used"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, - ruleId: "unused-1", + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), + ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "unused-2", - type: "disable", - line: 1, - column: 28, + ruleId: "unused-1", + type: "enable", + line: 3, + column: 1, justification: "j2" }, { parentComment, - ruleId: "used", - type: "disable", - line: 1, - column: 38, + ruleId: "unused-2", + type: "enable", + line: 4, + column: 1, justification: "j3" + }, + { + parentComment, + ruleId: "used", + type: "enable", + line: 5, + column: 1, + justification: "j4" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-1').", - line: 1, - column: 18, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-1').", + line: 3, + column: 1, fix: { - range: [18, 28], + range: [17, 27], text: "" }, severity: 2, @@ -1753,76 +3071,84 @@ describe("apply-disable-directives", () => { }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-2').", - line: 1, - column: 28, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-2').", + line: 4, + column: 1, fix: { - range: [26, 36], + range: [25, 35], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j3" }] } ] ); }); - it("Adds a problem for /* eslint-disable unused-1, unused-2, used, unused-3 */", () => { - const parentComment = createParentComment([0, 55], " eslint-disable unused-1, unused-2, used, unused-3 ", ["unused-1", "unused-2", "used", "unused-3"]); + it("Adds a problem for /* eslint-disable used */ /* (problem from used) */ /* eslint-enable unused-1, unused-2, used, unused-3 */", () => { + const parentComment = createParentComment([0, 55], " eslint-enable unused-1, unused-2, used, unused-3 ", ["unused-1", "unused-2", "used", "unused-3"]); assert.deepStrictEqual( applyDisableDirectives({ directives: [ { - parentComment, - ruleId: "unused-1", + parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), + ruleId: "used", type: "disable", line: 1, - column: 18, + column: 1, justification: "j1" }, { parentComment, - ruleId: "unused-2", - type: "disable", - line: 1, - column: 28, + ruleId: "unused-1", + type: "enable", + line: 3, + column: 1, justification: "j2" }, { parentComment, - ruleId: "used", - type: "disable", - line: 1, - column: 38, + ruleId: "unused-2", + type: "enable", + line: 4, + column: 1, justification: "j3" }, { parentComment, - ruleId: "unused-3", - type: "disable", - line: 1, - column: 43, + ruleId: "used", + type: "enable", + line: 5, + column: 1, justification: "j4" + }, + { + parentComment, + ruleId: "unused-3", + type: "enable", + line: 6, + column: 1, + justification: "j5" } ], problems: [{ line: 2, column: 1, ruleId: "used" }], reportUnusedDisableDirectives: "error" }), [ + { + line: 2, + column: 1, + ruleId: "used", + suppressions: [{ kind: "directive", justification: "j1" }] + }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-1').", - line: 1, - column: 18, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-1').", + line: 3, + column: 1, fix: { - range: [18, 28], + range: [17, 27], text: "" }, severity: 2, @@ -1830,11 +3156,11 @@ describe("apply-disable-directives", () => { }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-2').", - line: 1, - column: 28, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-2').", + line: 4, + column: 1, fix: { - range: [26, 36], + range: [25, 35], text: "" }, severity: 2, @@ -1842,28 +3168,22 @@ describe("apply-disable-directives", () => { }, { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-3').", - line: 1, - column: 43, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-3').", + line: 6, + column: 1, fix: { - range: [42, 52], + range: [41, 51], text: "" }, severity: 2, nodeType: null - }, - { - line: 2, - column: 1, - ruleId: "used", - suppressions: [{ kind: "directive", justification: "j3" }] } ] ); }); - it("Adds a problem for /* eslint-disable unused-1, unused-2 */", () => { - const parentComment = createParentComment([0, 39], " eslint-disable unused-1, unused-2 ", ["unused-1", "unused-2"]); + it("Adds a problem for /* eslint-enable unused-1, unused-2 */", () => { + const parentComment = createParentComment([0, 39], " eslint-enable unused-1, unused-2 ", ["unused-1", "unused-2"]); assert.deepStrictEqual( applyDisableDirectives({ @@ -1871,7 +3191,7 @@ describe("apply-disable-directives", () => { { parentComment, ruleId: "unused-1", - type: "disable", + type: "enable", line: 1, column: 18, justification: "j1" @@ -1879,7 +3199,7 @@ describe("apply-disable-directives", () => { { parentComment, ruleId: "unused-2", - type: "disable", + type: "enable", line: 1, column: 28, justification: "j2" @@ -1891,7 +3211,7 @@ describe("apply-disable-directives", () => { [ { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-1' or 'unused-2').", + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-1' or 'unused-2').", line: 1, column: 18, fix: { @@ -1905,8 +3225,8 @@ describe("apply-disable-directives", () => { ); }); - it("Adds a problem for /* eslint-disable unused-1, unused-2, unused-3 */", () => { - const parentComment = createParentComment([0, 49], " eslint-disable unused-1, unused-2, unused-3 ", ["unused-1", "unused-2", "unused-3"]); + it("Adds a problem for /* eslint-enable unused-1, unused-2, unused-3 */", () => { + const parentComment = createParentComment([0, 49], " eslint-enable unused-1, unused-2, unused-3 ", ["unused-1", "unused-2", "unused-3"]); assert.deepStrictEqual( applyDisableDirectives({ @@ -1914,21 +3234,21 @@ describe("apply-disable-directives", () => { { parentComment, ruleId: "unused-1", - type: "disable", + type: "enable", line: 1, column: 18 }, { parentComment, ruleId: "unused-2", - type: "disable", + type: "enable", line: 1, column: 28 }, { parentComment, ruleId: "unused-3", - type: "disable", + type: "enable", line: 1, column: 38 } @@ -1939,7 +3259,7 @@ describe("apply-disable-directives", () => { [ { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'unused-1', 'unused-2', or 'unused-3').", + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'unused-1', 'unused-2', or 'unused-3').", line: 1, column: 18, fix: { @@ -1952,72 +3272,5 @@ describe("apply-disable-directives", () => { ] ); }); - - it("Adds a problem for /* eslint-disable foo */ \\n (problem from foo and bar) // eslint-disable-line foo, bar", () => { - assert.deepStrictEqual( - applyDisableDirectives({ - directives: [ - { - parentComment: createParentComment([0, 29], " eslint-disable foo ", ["foo"]), - ruleId: "foo", - type: "disable", - line: 1, - column: 1, - justification: "j1" - }, - { - parentComment: createParentComment([41, 81], " eslint-disable-line foo, bar", ["foo", "bar"]), - ruleId: "foo", - type: "disable-line", - line: 2, - column: 11, - justification: "j2" - }, - { - parentComment: createParentComment([41, 81], " eslint-disable-line foo, bar ", ["foo", "bar"]), - ruleId: "bar", - type: "disable-line", - line: 2, - column: 11, - justification: "j2" - } - ], - problems: [ - { line: 2, column: 1, ruleId: "bar" }, - { line: 2, column: 6, ruleId: "foo" } - ], - reportUnusedDisableDirectives: "error" - }), - [ - { - ruleId: "bar", - line: 2, - column: 1, - suppressions: [{ kind: "directive", justification: "j2" }] - }, - { - ruleId: "foo", - line: 2, - column: 6, - suppressions: [ - { kind: "directive", justification: "j1" }, - { kind: "directive", justification: "j2" } - ] - }, - { - ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'foo').", - line: 2, - column: 11, - fix: { - range: [64, 69], - text: "" - }, - severity: 2, - nodeType: null - } - ] - ); - }); }); }); diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index c8fd4134caa..b89b073ecaf 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -4323,6 +4323,166 @@ var a = "test2"; assert.strictEqual(suppressedMessages.length, 0); }); + it("reports problems for unused eslint-enable comments", () => { + const messages = linter.verify("/* eslint-enable */", {}, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 1, + column: 1, + fix: { + range: [0, 19], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 0); + }); + + it("reports problems for unused eslint-enable comments with ruleId", () => { + const messages = linter.verify("/* eslint-enable no-alert */", {}, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'no-alert').", + line: 1, + column: 1, + fix: { + range: [0, 28], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 0); + }); + + it("reports problems for unused eslint-enable comments with mismatch ruleId", () => { + const code = [ + "/* eslint-disable no-alert */", + "alert(\"test\");", + "/* eslint-enable no-console */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'no-console').", + line: 3, + column: 1, + fix: { + range: [45, 75], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 1); + }); + + it("reports problems for unused eslint-enable comments with used eslint-enable comments", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\");", + "/* eslint-disable no-alert -- j2 */", + "alert(\"test\");", + "/* eslint-enable no-alert -- j3 */", + "/* eslint-enable -- j4 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 6, + column: 1, + fix: { + range: [137, 162], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 2); + }); + + it("reports problems for unused eslint-disable comments with used eslint-enable comments", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "console.log(\"test\"); //", + "/* eslint-enable no-alert -- j2 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'no-alert').", + line: 1, + column: 1, + fix: { + range: [0, 35], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 0); + }); + it("reports problems for unused eslint-disable comments (in config)", () => { const messages = linter.verify("/* eslint-disable */", { reportUnusedDisableDirectives: true }); const suppressedMessages = linter.getSuppressedMessages(); @@ -4407,12 +4567,156 @@ var a = "test2"; assert.strictEqual(suppressedMessages[0].ruleId, "no-fallthrough"); }); + it("reports problems for multiple eslint-enable comments with same ruleId", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable no-alert -- j3 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments without ruleId (Rule is already enabled)", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable -- j3 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments with ruleId (Rule is already enabled by eslint-enable comments without ruleId)", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable -- j3 */", + "/* eslint-enable no-alert -- j2 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); + + it("reports problems for eslint-enable comments without ruleId (Two rules are already enabled)", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable no-console -- j3 */", + "/* eslint-enable -- j4 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2, + "no-console": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 6); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments with ruleId (Two rules are already enabled by eslint-enable comments without ruleId)", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable -- j2 */", + "/* eslint-enable no-console -- j3 */", + "/* eslint-enable no-alert -- j4 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2, + "no-console": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 2); + assert.strictEqual(messages[0].line, 5); + assert.strictEqual(messages[1].line, 6); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable no-console -- j2 */", + "/* eslint-enable -- j3 */", + "/* eslint-enable no-alert -- j4 */", + "/* eslint-enable -- j5 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2, + "no-console": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 2); + assert.strictEqual(messages[0].line, 6); + assert.strictEqual(messages[1].line, 7); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); + }); + describe("autofix", () => { const alwaysReportsRule = { create(context) { return { Program(node) { context.report({ message: "bad code", loc: node.loc.end }); + }, + "Identifier[name=bad]"(node) { + context.report({ message: "bad id", loc: node.loc }); } }; } @@ -4482,6 +4786,10 @@ var a = "test2"; code: "/* eslint-disable \nunused\n*/", output: " " }, + { + code: "/* eslint-enable \nunused\n*/", + output: " " + }, //----------------------------------------------- // Removing only individual rules @@ -4520,6 +4828,26 @@ var a = "test2"; code: "/*\u00A0eslint-disable unused, used*/", output: "/*\u00A0eslint-disable used*/" }, + { + code: "/* eslint-disable used*/ bad /*\neslint-enable unused, used*/", + output: "/* eslint-disable used*/ bad /*\neslint-enable used*/" + }, + { + code: "/* eslint-disable used*/ bad /*\n eslint-enable unused, used*/", + output: "/* eslint-disable used*/ bad /*\n eslint-enable used*/" + }, + { + code: "/* eslint-disable used*/ bad /*\r\neslint-enable unused, used*/", + output: "/* eslint-disable used*/ bad /*\r\neslint-enable used*/" + }, + { + code: "/* eslint-disable used*/ bad /*\u2028eslint-enable unused, used*/", + output: "/* eslint-disable used*/ bad /*\u2028eslint-enable used*/" + }, + { + code: "/* eslint-disable used*/ bad /*\u00A0eslint-enable unused, used*/", + output: "/* eslint-disable used*/ bad /*\u00A0eslint-enable used*/" + }, { code: "// eslint-disable-line unused, used", output: "// eslint-disable-line used" @@ -4544,6 +4872,26 @@ var a = "test2"; code: "/* eslint-disable\u00A0unused, used*/", output: "/* eslint-disable\u00A0used*/" }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable\nunused, used*/", + output: "/* eslint-disable used*/ bad /* eslint-enable\nused*/" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable\n unused, used*/", + output: "/* eslint-disable used*/ bad /* eslint-enable\n used*/" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable\r\nunused, used*/", + output: "/* eslint-disable used*/ bad /* eslint-enable\r\nused*/" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable\u2028unused, used*/", + output: "/* eslint-disable used*/ bad /* eslint-enable\u2028used*/" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable\u00A0unused, used*/", + output: "/* eslint-disable used*/ bad /* eslint-enable\u00A0used*/" + }, // when removing the first rule, the comma and all whitespace up to the next rule (or next lone comma) should also be removed { @@ -4578,6 +4926,18 @@ var a = "test2"; code: "/* eslint-disable unused\u2028,\u2028used */", output: "/* eslint-disable used */" }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable unused\n,\nused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable unused \n \n,\n\n used */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable unused\u2028,\u2028used */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, { code: "// eslint-disable-line unused\u00A0,\u00A0used", output: "// eslint-disable-line used" @@ -4632,6 +4992,18 @@ var a = "test2"; code: "/* eslint-disable used-1,\u2028unused\u2028,used-2 */", output: "/* eslint-disable used-1,used-2 */" }, + { + code: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,\nunused\n,used-2 */", + output: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,used-2 */" + }, + { + code: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,\n\n unused \n \n ,used-2 */", + output: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,used-2 */" + }, + { + code: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,\u2028unused\u2028,used-2 */", + output: "/* eslint-disable used-1, used-2*/ bad /* eslint-enable used-1,used-2 */" + }, { code: "// eslint-disable-line used-1,\u00A0unused\u00A0,used-2", output: "// eslint-disable-line used-1,used-2" @@ -4666,6 +5038,14 @@ var a = "test2"; code: "/* eslint-disable used-1\u2028,unused,\u2028used-2 */", output: "/* eslint-disable used-1\u2028,\u2028used-2 */" }, + { + code: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1\n,unused,\nused-2 */", + output: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1\n,\nused-2 */" + }, + { + code: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1\u2028,unused,\u2028used-2 */", + output: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1\u2028,\u2028used-2 */" + }, { code: "// eslint-disable-line used-1\u00A0,unused,\u00A0used-2", output: "// eslint-disable-line used-1\u00A0,\u00A0used-2" @@ -4690,6 +5070,18 @@ var a = "test2"; code: "/* eslint-disable used-1,\n,unused,\n,used-2 */", output: "/* eslint-disable used-1,\n,\n,used-2 */" }, + { + code: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,\n,unused,used-2 */", + output: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,\n,used-2 */" + }, + { + code: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,unused,\n,used-2 */", + output: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,\n,used-2 */" + }, + { + code: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,\n,unused,\n,used-2 */", + output: "/* eslint-disable used-1, used-2 */ bad /* eslint-enable used-1,\n,\n,used-2 */" + }, { code: "// eslint-disable-line used, unused,", output: "// eslint-disable-line used," @@ -4710,6 +5102,10 @@ var a = "test2"; code: "/* eslint-disable used, unused,\n*/", output: "/* eslint-disable used,\n*/" }, + { + code: "/* eslint-disable used */ bad /* eslint-enable used, unused,\n*/", + output: "/* eslint-disable used */ bad /* eslint-enable used,\n*/" + }, // when removing the last rule, the comma and all whitespace up to the previous rule (or previous lone comma) should also be removed { @@ -4748,6 +5144,18 @@ var a = "test2"; code: "/* eslint-disable used\u2028,\u2028unused */", output: "/* eslint-disable used */" }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used\n,\nunused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used \n \n,\n\n unused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used\u2028,\u2028unused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used */" + }, { code: "// eslint-disable-line used\u00A0,\u00A0unused", output: "// eslint-disable-line used" @@ -4768,6 +5176,14 @@ var a = "test2"; code: "/* eslint-disable used\n, ,unused */", output: "/* eslint-disable used\n, */" }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used,\n,unused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used, */" + }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used\n, ,unused */", + output: "/* eslint-disable used*/ bad /* eslint-enable used\n, */" + }, // content after the last rule should not be changed { @@ -4798,6 +5214,10 @@ var a = "test2"; code: "/* eslint-disable used,unused\u2028*/", output: "/* eslint-disable used\u2028*/" }, + { + code: "/* eslint-disable used*/ bad /* eslint-enable used,unused\u2028*/", + output: "/* eslint-disable used*/ bad /* eslint-enable used\u2028*/" + }, { code: "// eslint-disable-line used,unused\u00A0", output: "// eslint-disable-line used\u00A0" @@ -4813,34 +5233,172 @@ var a = "test2"; output: "// eslint-disable-line used" }, { - code: "// eslint-disable-line unused-1, unused-2, used", - output: "// eslint-disable-line used" + code: "// eslint-disable-line unused-1, unused-2, used", + output: "// eslint-disable-line used" + }, + { + code: "// eslint-disable-line used-1, unused-1, used-2, unused-2", + output: "// eslint-disable-line used-1, used-2" + }, + { + code: "// eslint-disable-line unused-1, used-1, unused-2, used-2", + output: "// eslint-disable-line used-1, used-2" + }, + { + code: ` + /* eslint-disable unused-1, + used-1, + unused-2, + used-2 + */ + `, + output: ` + /* eslint-disable used-1, + used-2 + */ + ` + }, + { + code: ` + /* eslint-disable + unused-1, + used-1, + unused-2, + used-2 + */ + `, + output: ` + /* eslint-disable + used-1, + used-2 + */ + ` + }, + { + code: ` + /* eslint-disable + used-1, + unused-1, + used-2, + unused-2 + */ + `, + output: ` + /* eslint-disable + used-1, + used-2 + */ + ` + }, + { + code: ` + /* eslint-disable + used-1, + unused-1, + used-2, + unused-2, + */ + `, + output: ` + /* eslint-disable + used-1, + used-2, + */ + ` + }, + { + code: ` + /* eslint-disable + ,unused-1 + ,used-1 + ,unused-2 + ,used-2 + */ + `, + output: ` + /* eslint-disable + ,used-1 + ,used-2 + */ + ` + }, + { + code: ` + /* eslint-disable + ,used-1 + ,unused-1 + ,used-2 + ,unused-2 + */ + `, + output: ` + /* eslint-disable + ,used-1 + ,used-2 + */ + ` }, { - code: "// eslint-disable-line used-1, unused-1, used-2, unused-2", - output: "// eslint-disable-line used-1, used-2" + code: ` + /* eslint-disable + used-1, + unused-1, + used-2, + unused-2 + + -- comment + */ + `, + output: ` + /* eslint-disable + used-1, + used-2 + + -- comment + */ + ` }, { - code: "// eslint-disable-line unused-1, used-1, unused-2, used-2", - output: "// eslint-disable-line used-1, used-2" + code: ` + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable unused-1, + used-1, + unused-2, + used-2 + */ + `, + output: ` + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, + used-2 + */ + ` }, { code: ` - /* eslint-disable unused-1, + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable unused-1, used-1, unused-2, used-2 */ `, output: ` - /* eslint-disable used-1, + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, used-2 */ ` }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable unused-1, used-1, unused-2, @@ -4848,7 +5406,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, used-2 */ @@ -4856,7 +5416,9 @@ var a = "test2"; }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, unused-1, used-2, @@ -4864,7 +5426,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, used-2 */ @@ -4872,7 +5436,9 @@ var a = "test2"; }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, unused-1, used-2, @@ -4880,7 +5446,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, used-2, */ @@ -4888,7 +5456,9 @@ var a = "test2"; }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable ,unused-1 ,used-1 ,unused-2 @@ -4896,7 +5466,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable ,used-1 ,used-2 */ @@ -4904,7 +5476,9 @@ var a = "test2"; }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable ,used-1 ,unused-1 ,used-2 @@ -4912,7 +5486,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable ,used-1 ,used-2 */ @@ -4920,7 +5496,9 @@ var a = "test2"; }, { code: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, unused-1, used-2, @@ -4930,7 +5508,9 @@ var a = "test2"; */ `, output: ` - /* eslint-disable + /* eslint-disable used-1, used-2*/ + bad + /* eslint-enable used-1, used-2 @@ -15015,82 +15595,373 @@ var a = "test2"; ); }); - it("reports problems for partially unused eslint-disable-next-line comments (in config)", () => { - const code = "// eslint-disable-next-line no-alert, no-redeclare \nalert('test');"; + it("reports problems for partially unused eslint-disable-next-line comments (in config)", () => { + const code = "// eslint-disable-next-line no-alert, no-redeclare \nalert('test');"; + const config = { + linterOptions: { + reportUnusedDisableDirectives: true + }, + rules: { + "no-alert": 1, + "no-redeclare": 1 + } + }; + + const messages = linter.verify(code, config, { + filename, + allowInlineConfig: true + }); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'no-redeclare').", + line: 1, + column: 1, + fix: { + range: [36, 50], + text: "" + }, + severity: 1, + nodeType: null + } + ] + ); + }); + + it("reports problems for partially unused multiline eslint-disable-next-line comments (in config)", () => { + const code = ` + /* eslint-disable-next-line no-alert, no-redeclare -- + * Here's a very long description about why this configuration is necessary + * along with some additional information + **/ + alert('test'); + `; + const config = { + linterOptions: { + reportUnusedDisableDirectives: true + }, + rules: { + "no-alert": 1, + "no-redeclare": 1 + } + }; + + const messages = linter.verify(code, config, { + filename, + allowInlineConfig: true + }); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-disable directive (no problems were reported from 'no-redeclare').", + line: 2, + column: 21, + fix: { + range: [57, 71], + text: "" + }, + severity: 1, + nodeType: null + } + ] + ); + }); + + it("reports problems for unused eslint-enable comments", () => { + const messages = linter.verify("/* eslint-enable */", {}, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 1, + column: 1, + fix: { + range: [0, 19], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 0); + }); + + it("reports problems for unused eslint-enable comments with ruleId", () => { + const messages = linter.verify("/* eslint-enable no-alert */", {}, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'no-alert').", + line: 1, + column: 1, + fix: { + range: [0, 28], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 0); + }); + + it("reports problems for unused eslint-enable comments with mismatch ruleId", () => { + const code = [ + "/* eslint-disable no-alert */", + "alert(\"test\");", + "/* eslint-enable no-console */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found for 'no-console').", + line: 3, + column: 1, + fix: { + range: [45, 75], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 1); + }); + + it("reports problems for unused eslint-enable comments with used eslint-enable comments", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\");", + "/* eslint-disable no-alert -- j2 */", + "alert(\"test\");", + "/* eslint-enable no-alert -- j3 */", + "/* eslint-enable -- j4 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.deepStrictEqual( + messages, + [ + { + ruleId: null, + message: "Unused eslint-enable directive (no matching eslint-disable directives were found).", + line: 6, + column: 1, + fix: { + range: [137, 162], + text: " " + }, + severity: 2, + nodeType: null + } + ] + ); + + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 2); + }); + + it("reports problems for multiple eslint-enable comments with same ruleId", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable no-alert -- j3 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments without ruleId (Rule is already enabled)", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable -- j3 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments with ruleId (Rule is already enabled by eslint-enable comments without ruleId)", () => { + const code = [ + "/* eslint-disable no-alert -- j1 */", + "alert(\"test\"); //", + "/* eslint-enable -- j3 */", + "/* eslint-enable no-alert -- j2 */" + ].join("\n"); const config = { - linterOptions: { - reportUnusedDisableDirectives: true - }, rules: { - "no-alert": 1, - "no-redeclare": 1 + "no-alert": 2 } }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); - const messages = linter.verify(code, config, { - filename, - allowInlineConfig: true - }); + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 4); + assert.strictEqual(suppressedMessages.length, 1); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + }); - assert.deepStrictEqual( - messages, - [ - { - ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'no-redeclare').", - line: 1, - column: 1, - fix: { - range: [36, 50], - text: "" - }, - severity: 1, - nodeType: null - } - ] - ); + it("reports problems for eslint-enable comments without ruleId (Two rules are already enabled)", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable no-alert -- j2 */", + "/* eslint-enable no-console -- j3 */", + "/* eslint-enable -- j4 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2, + "no-console": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 1); + assert.strictEqual(messages[0].line, 6); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); }); - it("reports problems for partially unused multiline eslint-disable-next-line comments (in config)", () => { - const code = ` - /* eslint-disable-next-line no-alert, no-redeclare -- - * Here's a very long description about why this configuration is necessary - * along with some additional information - **/ - alert('test'); - `; + it("reports problems for multiple eslint-enable comments with ruleId (Two rules are already enabled by eslint-enable comments without ruleId)", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable -- j2 */", + "/* eslint-enable no-console -- j3 */", + "/* eslint-enable no-alert -- j4 */" + ].join("\n"); const config = { - linterOptions: { - reportUnusedDisableDirectives: true - }, rules: { - "no-alert": 1, - "no-redeclare": 1 + "no-alert": 2, + "no-console": 2 } }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); - const messages = linter.verify(code, config, { - filename, - allowInlineConfig: true - }); + assert.strictEqual(messages.length, 2); + assert.strictEqual(messages[0].line, 5); + assert.strictEqual(messages[1].line, 6); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); + }); + + it("reports problems for multiple eslint-enable comments", () => { + const code = [ + "/* eslint-disable no-alert, no-console -- j1 */", + "alert(\"test\"); //", + "console.log(\"test\"); //", + "/* eslint-enable no-console -- j2 */", + "/* eslint-enable -- j3 */", + "/* eslint-enable no-alert -- j4 */", + "/* eslint-enable -- j5 */" + ].join("\n"); + const config = { + rules: { + "no-alert": 2, + "no-console": 2 + } + }; + const messages = linter.verify(code, config, { reportUnusedDisableDirectives: true }); + const suppressedMessages = linter.getSuppressedMessages(); + + assert.strictEqual(messages.length, 2); + assert.strictEqual(messages[0].line, 6); + assert.strictEqual(messages[1].line, 7); + assert.strictEqual(suppressedMessages.length, 2); + assert.strictEqual(suppressedMessages[0].suppressions.length, 1); + assert.strictEqual(suppressedMessages[1].suppressions.length, 1); + }); + + it("reports problems for unused eslint-disable comments (warn)", () => { + const messages = linter.verify("/* eslint-disable */", {}, { reportUnusedDisableDirectives: "warn" }); + const suppressedMessages = linter.getSuppressedMessages(); assert.deepStrictEqual( messages, [ { ruleId: null, - message: "Unused eslint-disable directive (no problems were reported from 'no-redeclare').", - line: 2, - column: 21, + message: "Unused eslint-disable directive (no problems were reported).", + line: 1, + column: 1, fix: { - range: [57, 71], - text: "" + range: [0, 20], + text: " " }, severity: 1, nodeType: null } ] ); + + assert.strictEqual(suppressedMessages.length, 0); }); describe("autofix", () => { @@ -15099,6 +15970,9 @@ var a = "test2"; return { Program(node) { context.report({ message: "bad code", loc: node.loc.end }); + }, + "Identifier[name=bad]"(node) { + context.report({ message: "bad id", loc: node.loc }); } }; } @@ -15177,6 +16051,10 @@ var a = "test2"; code: "/* eslint-disable \ntest/unused\n*/", output: " " }, + { + code: "/* eslint-enable \ntest/unused\n*/", + output: " " + }, //----------------------------------------------- // Removing only individual rules @@ -15215,6 +16093,26 @@ var a = "test2"; code: "/*\u00A0eslint-disable test/unused, test/used*/", output: "/*\u00A0eslint-disable test/used*/" }, + { + code: "/* eslint-disable test/used */ bad /*\neslint-enable test/unused, test/used*/", + output: "/* eslint-disable test/used */ bad /*\neslint-enable test/used*/" + }, + { + code: "/* eslint-disable test/used */ bad /*\n eslint-enable test/unused, test/used*/", + output: "/* eslint-disable test/used */ bad /*\n eslint-enable test/used*/" + }, + { + code: "/* eslint-disable test/used */ bad /*\r\neslint-enable test/unused, test/used*/", + output: "/* eslint-disable test/used */ bad /*\r\neslint-enable test/used*/" + }, + { + code: "/* eslint-disable test/used */ bad /*\u2028eslint-enable test/unused, test/used*/", + output: "/* eslint-disable test/used */ bad /*\u2028eslint-enable test/used*/" + }, + { + code: "/* eslint-disable test/used */ bad /*\u00A0eslint-enable test/unused, test/used*/", + output: "/* eslint-disable test/used */ bad /*\u00A0eslint-enable test/used*/" + }, { code: "// eslint-disable-line test/unused, test/used", output: "// eslint-disable-line test/used" @@ -15273,6 +16171,18 @@ var a = "test2"; code: "/* eslint-disable test/unused\u2028,\u2028test/used */", output: "/* eslint-disable test/used */" }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/unused\n,\ntest/used */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/unused \n \n,\n\n test/used */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/unused\u2028,\u2028test/used */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, { code: "// eslint-disable-line test/unused\u00A0,\u00A0test/used", output: "// eslint-disable-line test/used" @@ -15327,6 +16237,18 @@ var a = "test2"; code: "/* eslint-disable test/used-1,\u2028test/unused\u2028,test/used-2 */", output: "/* eslint-disable test/used-1,test/used-2 */" }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\ntest/unused\n,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,test/used-2 */" + }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n\n test/unused \n \n ,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,test/used-2 */" + }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\u2028test/unused\u2028,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,test/used-2 */" + }, { code: "// eslint-disable-line test/used-1,\u00A0test/unused\u00A0,test/used-2", output: "// eslint-disable-line test/used-1,test/used-2" @@ -15361,6 +16283,14 @@ var a = "test2"; code: "/* eslint-disable test/used-1\u2028,test/unused,\u2028test/used-2 */", output: "/* eslint-disable test/used-1\u2028,\u2028test/used-2 */" }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1\n,test/unused,\ntest/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1\n,\ntest/used-2 */" + }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1\u2028,test/unused,\u2028test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1\u2028,\u2028test/used-2 */" + }, { code: "// eslint-disable-line test/used-1\u00A0,test/unused,\u00A0test/used-2", output: "// eslint-disable-line test/used-1\u00A0,\u00A0test/used-2" @@ -15385,6 +16315,18 @@ var a = "test2"; code: "/* eslint-disable test/used-1,\n,test/unused,\n,test/used-2 */", output: "/* eslint-disable test/used-1,\n,\n,test/used-2 */" }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n,test/unused,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n,test/used-2 */" + }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,test/unused,\n,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n,test/used-2 */" + }, + { + code: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n,test/unused,\n,test/used-2 */", + output: "/* eslint-disable test/used-1, test/used-2 */ bad /* eslint-enable test/used-1,\n,\n,test/used-2 */" + }, { code: "// eslint-disable-line test/used, test/unused,", output: "// eslint-disable-line test/used," @@ -15405,6 +16347,10 @@ var a = "test2"; code: "/* eslint-disable test/used, test/unused,\n*/", output: "/* eslint-disable test/used,\n*/" }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used, test/unused,\n*/", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used,\n*/" + }, // when removing the last rule, the comma and all whitespace up to the previous rule (or previous lone comma) should also be removed { @@ -15443,6 +16389,18 @@ var a = "test2"; code: "/* eslint-disable test/used\u2028,\u2028test/unused */", output: "/* eslint-disable test/used */" }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used\n,\ntest/unused */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used \n \n,\n\n test/unused */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used\u2028,\u2028test/unused */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used */" + }, { code: "// eslint-disable-line test/used\u00A0,\u00A0test/unused", output: "// eslint-disable-line test/used" @@ -15463,6 +16421,14 @@ var a = "test2"; code: "/* eslint-disable test/used\n, ,test/unused */", output: "/* eslint-disable test/used\n, */" }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used,\n,test/unused */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used, */" + }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used\n, ,test/unused */", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used\n, */" + }, // content after the last rule should not be changed { @@ -15493,6 +16459,10 @@ var a = "test2"; code: "/* eslint-disable test/used,test/unused\u2028*/", output: "/* eslint-disable test/used\u2028*/" }, + { + code: "/* eslint-disable test/used */ bad /* eslint-enable test/used,test/unused\u2028*/", + output: "/* eslint-disable test/used */ bad /* eslint-enable test/used\u2028*/" + }, { code: "// eslint-disable-line test/used,test/unused\u00A0", output: "// eslint-disable-line test/used\u00A0" @@ -15633,6 +16603,148 @@ var a = "test2"; */ ` }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable test/unused-1, + test/used-1, + test/unused-2, + test/used-2 + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable test/used-1, + test/used-2 + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/unused-1, + test/used-1, + test/unused-2, + test/used-2 + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/used-2 + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/unused-1, + test/used-2, + test/unused-2 + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/used-2 + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/unused-1, + test/used-2, + test/unused-2, + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/used-2, + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + ,test/unused-1 + ,test/used-1 + ,test/unused-2 + ,test/used-2 + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + ,test/used-1 + ,test/used-2 + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + ,test/used-1 + ,test/unused-1 + ,test/used-2 + ,test/unused-2 + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + ,test/used-1 + ,test/used-2 + */ + ` + }, + { + code: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/unused-1, + test/used-2, + test/unused-2 + + -- comment + */ + `, + output: ` + /* eslint-disable test/used-1, test/used-2 */ + bad + /* eslint-enable + test/used-1, + test/used-2 + + -- comment + */ + ` + }, // duplicates in the list {