Repository: eslint/eslint (js)

Issue:
Support block-comment version of eslint-disable-line
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).

    This template is for bug reports. If you are reporting a bug, please continue on. If you are here for another reason, please see below:

    1. To propose a new rule: http://eslint.org/docs/developer-guide/contributing/new-rules
    2. To request a change: http://eslint.org/docs/developer-guide/contributing/changes
    3. If you have any questions, please stop by our chatroom: https://gitter.im/eslint/eslint

    Note that leaving sections blank will make it difficult for us to troubleshoot and we may have to close the issue.
-->

**Tell us about your environment**

* **ESLint Version:** master
* **Node Version:** any
* **npm Version:** any

**What parser (default, Babel-ESLint, etc.) are you using?**
default

**Please show your full configuration:**

<!-- Paste your configuration below: -->
```
{ "rules": { "no-alert": [1] } }
```

**What did you do? Please include the actual source code causing the issue.**

<!-- Paste the source code below: -->
```js
/* eslint-disable-line */ alert(1);
```

**What did you expect to happen?**

It should work like in JSCS:
```js
/* jscs:ignore */ alert(1)
```

**What actually happened? Please include the actual, raw output from ESLint.**

Error reported.


Pull request description:
Update: support eslint-disable-* block comments (fixes #8781)
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[ ] Documentation update
[ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ X] Add something to the core
[ ] Other, please explain:

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**
Updated block comments to support `eslint-disable-line` and `eslint-disable-next-line`

**Is there anything you'd like reviewers to focus on?**
Nope! 


Patch:
diff --git a/docs/developer-guide/nodejs-api.md b/docs/developer-guide/nodejs-api.md
index c774666e0..4988f2696 100644
--- a/docs/developer-guide/nodejs-api.md
+++ b/docs/developer-guide/nodejs-api.md
@@ -496,7 +496,7 @@ If the operation ends with a parsing error, you will get a single message for th
             warningCount: 0,
             fixableErrorCount: 0,
             fixableWarningCount: 0,
-            source: "fucntion foo() {}"
+            source: "function foo() {}"
         }
     ],
     errorCount: 1,
diff --git a/docs/rules/max-len.md b/docs/rules/max-len.md
index 71339f01c..7aa755a34 100644
--- a/docs/rules/max-len.md
+++ b/docs/rules/max-len.md
@@ -147,7 +147,7 @@ var longRegExpLiteral = /this is a really really really really really long regul
 Examples of **correct** code for this rule with the `ignorePattern` option:
 
 ```js
-/*eslint max-len: ["error", { "ignorePattern": "^\\s*var\\s.+=\\s*require\\s*\(" }]*/
+/*eslint max-len: ["error", { "ignorePattern": "^\\s*var\\s.+=\\s*require\\s*\\(" }]*/
 
 var dep = require('really/really/really/really/really/really/really/really/long/module');
 ```
diff --git a/docs/rules/valid-typeof.md b/docs/rules/valid-typeof.md
index 2ce02b490..60539eecb 100644
--- a/docs/rules/valid-typeof.md
+++ b/docs/rules/valid-typeof.md
@@ -20,7 +20,7 @@ Examples of **incorrect** code for this rule:
 typeof foo === "strnig"
 typeof foo == "undefimed"
 typeof bar != "nunber"
-typeof bar !== "fucntion"
+typeof bar !== "function"
 ```
 
 Examples of **correct** code for this rule:
diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md
index 098fcdf43..5d4f93d55 100644
--- a/docs/user-guide/configuring.md
+++ b/docs/user-guide/configuring.md
@@ -394,13 +394,18 @@ You can also disable or enable specific rules for an entire file:
 alert('foo');
 ```
 
-To disable all rules on a specific line, use a line comment in one of the following formats:
+To disable all rules on a specific line, use a line or block comment in one of the following formats:
 
 ```js
 alert('foo'); // eslint-disable-line
 
 // eslint-disable-next-line
 alert('foo');
+
+/* eslint-disable-next-line */
+alert('foo');
+
+alert('foo'); /* eslint-disable-line */
 ```
 
 To disable a specific rule on a specific line:
@@ -410,6 +415,11 @@ alert('foo'); // eslint-disable-line no-alert
 
 // eslint-disable-next-line no-alert
 alert('foo');
+
+alert('foo'); /* eslint-disable-line no-alert */
+
+/* eslint-disable-next-line no-alert */
+alert('foo');
 ```
 
 To disable multiple rules on a specific line:
@@ -419,12 +429,18 @@ alert('foo'); // eslint-disable-line no-alert, quotes, semi
 
 // eslint-disable-next-line no-alert, quotes, semi
 alert('foo');
+
+alert('foo'); /* eslint-disable-line no-alert, quotes, semi */
+
+/* eslint-disable-next-line no-alert, quotes, semi */
+alert('foo');
 ```
 
 All of the above methods also work for plugin rules. For example, to disable `eslint-plugin-example`'s `rule-name` rule, combine the plugin's name (`example`) and the rule's name (`rule-name`) into `example/rule-name`:
 
 ```js
 foo(); // eslint-disable-line example/rule-name
+foo(); /* eslint-disable-line example/rule-name */
 ```
 
 **Note:** Comments that disable warnings for a portion of a file tell ESLint not to report rule violations for the disabled code. ESLint still parses the entire file, however, so disabled code still needs to be syntactically valid JavaScript.
diff --git a/lib/linter.js b/lib/linter.js
index d71a79a7c..8e95c3a71 100755
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -307,7 +307,6 @@ function modifyConfigsFromComments(filename, ast, config, ruleMapper) {
 
         if (match) {
             value = value.slice(match.index + match[1].length);
-
             if (comment.type === "Block") {
                 switch (match[1]) {
                     case "exported":
@@ -323,6 +322,18 @@ function modifyConfigsFromComments(filename, ast, config, ruleMapper) {
                         [].push.apply(disableDirectives, createDisableDirectives("disable", comment.loc.start, value));
                         break;
 
+                    case "eslint-disable-line":
+                        if (comment.loc.start.line === comment.loc.end.line) {
+                            [].push.apply(disableDirectives, createDisableDirectives("disable-line", comment.loc.start, value));
+                        }
+                        break;
+
+                    case "eslint-disable-next-line":
+                        if (comment.loc.start.line === comment.loc.end.line) {
+                            [].push.apply(disableDirectives, createDisableDirectives("disable-next-line", comment.loc.start, value));
+                        }
+                        break;
+
                     case "eslint-enable":
                         [].push.apply(disableDirectives, createDisableDirectives("enable", comment.loc.start, value));
                         break;


Test patch:
diff --git a/tests/lib/linter.js b/tests/lib/linter.js
index fc4298d56..5f42ffd9c 100644
--- a/tests/lib/linter.js
+++ b/tests/lib/linter.js
@@ -1889,7 +1889,7 @@ describe("Linter", () => {
         });
     });
 
-    describe("when evaluating code with comments to ignore reporting on of specific rules on a specific line", () => {
+    describe("when evaluating code with comments to ignore reporting on specific rules on a specific line", () => {
 
         describe("eslint-disable-line", () => {
             it("should report a violation", () => {
@@ -1931,14 +1931,15 @@ describe("Linter", () => {
                 assert.strictEqual(messages[0].ruleId, "no-alert");
             });
 
-            it("should report a violation", () => {
+            it("should report a violation if eslint-disable-line in a block comment is not on a single line", () => {
                 const code = [
-                    "alert('test'); // eslint-disable-line no-alert",
-                    "alert('test'); /*eslint-disable-line no-alert*/" // here
+                    "/* eslint-disable-line",
+                    "*",
+                    "*/ console.log('test');" // here
                 ].join("\n");
                 const config = {
                     rules: {
-                        "no-alert": 1
+                        "no-console": 1
                     }
                 };
 
@@ -1946,7 +1947,44 @@ describe("Linter", () => {
 
                 assert.strictEqual(messages.length, 1);
 
+                assert.strictEqual(messages[0].ruleId, "no-console");
+            });
+
+            it("should report a violation if eslint-disable-line in a block comment is not on a single line", () => {
+                const code = [
+                    "alert('test'); /* eslint-disable-line ",
+                    "no-alert */"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        quotes: [1, "double"],
+                        semi: [1, "always"]
+                    }
+                };
+
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 2);
+
                 assert.strictEqual(messages[0].ruleId, "no-alert");
+                assert.strictEqual(messages[1].ruleId, "quotes");
+            });
+
+            it("should not report a violation for eslint-disable-line in block comment", () => {
+                const code = [
+                    "alert('test'); // eslint-disable-line no-alert",
+                    "alert('test'); /*eslint-disable-line no-alert*/"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1
+                    }
+                };
+
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 0);
             });
 
             it("should not report a violation", () => {
@@ -1984,6 +2022,40 @@ describe("Linter", () => {
 
                 assert.strictEqual(messages.length, 0);
             });
+
+            it("should not report a violation", () => {
+                const code = [
+                    "alert('test') /* eslint-disable-line no-alert, quotes, semi */",
+                    "console.log('test'); /* eslint-disable-line */"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        quotes: [1, "double"],
+                        semi: [1, "always"],
+                        "no-console": 1
+                    }
+                };
+
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 0);
+            });
+
+            it("should ignore violations of multiple rules when specified in mixed comments", () => {
+                const code = [
+                    " alert(\"test\"); /* eslint-disable-line no-alert */ // eslint-disable-line quotes"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        quotes: [1, "single"]
+                    }
+                };
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 0);
+            });
         });
 
         describe("eslint-disable-next-line", () => {
@@ -2005,6 +2077,54 @@ describe("Linter", () => {
                 assert.strictEqual(messages[0].ruleId, "no-console");
             });
 
+            it("should ignore violation of specified rule if eslint-disable-next-line is a block comment", () => {
+                const code = [
+                    "/* eslint-disable-next-line no-alert */",
+                    "alert('test');",
+                    "console.log('test');"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        "no-console": 1
+                    }
+                };
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].ruleId, "no-console");
+            });
+            it("should ignore violation of specified rule if eslint-disable-next-line is a block comment", () => {
+                const code = [
+                    "/* eslint-disable-next-line no-alert */",
+                    "alert('test');"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1
+                    }
+                };
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 0);
+            });
+
+            it("should not ignore violation if block comment is not on a single line", () => {
+                const code = [
+                    "/* eslint-disable-next-line",
+                    "no-alert */alert('test');"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1
+                    }
+                };
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].ruleId, "no-alert");
+            });
+
             it("should ignore violations only of specified rule", () => {
                 const code = [
                     "// eslint-disable-next-line no-console",
@@ -2043,6 +2163,22 @@ describe("Linter", () => {
                 assert.strictEqual(messages[0].ruleId, "no-console");
             });
 
+            it("should ignore violations of multiple rules when specified in mixed comments", () => {
+                const code = [
+                    "/* eslint-disable-next-line no-alert */ // eslint-disable-next-line quotes",
+                    "alert(\"test\");"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        quotes: [1, "single"]
+                    }
+                };
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 0);
+            });
+
             it("should ignore violations of only the specified rule on next line", () => {
                 const code = [
                     "// eslint-disable-next-line quotes",
@@ -2103,7 +2239,7 @@ describe("Linter", () => {
                 assert.strictEqual(messages[0].ruleId, "no-console");
             });
 
-            it("should not ignore violations if comment is in block quotes", () => {
+            it("should ignore violations if eslint-disable-next-line is a block comment", () => {
                 const code = [
                     "alert('test');",
                     "/* eslint-disable-next-line no-alert */",
@@ -2118,10 +2254,30 @@ describe("Linter", () => {
                 };
                 const messages = linter.verify(code, config, filename);
 
-                assert.strictEqual(messages.length, 3);
+                assert.strictEqual(messages.length, 2);
                 assert.strictEqual(messages[0].ruleId, "no-alert");
-                assert.strictEqual(messages[1].ruleId, "no-alert");
-                assert.strictEqual(messages[2].ruleId, "no-console");
+                assert.strictEqual(messages[1].ruleId, "no-console");
+            });
+
+            it("should report a violation", () => {
+                const code = [
+                    "/* eslint-disable-next-line",
+                    "*",
+                    "*/",
+                    "console.log('test');" // here
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        "no-console": 1
+                    }
+                };
+
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 1);
+
+                assert.strictEqual(messages[0].ruleId, "no-console");
             });
 
             it("should not ignore violations if comment is of the type Shebang", () => {