Repository: eslint/eslint
Pull request #10565 (2018-07-05 17:52:55)

Chore: small refactor config-validator.js
<!--
    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)**

[x] 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)**
small refactor config-validator.js

**Is there anything you'd like reviewers to focus on?**
a simple micro bench: http://jsben.ch/jX6IZ




Patch:
diff --git a/.eslintrc.js b/.eslintrc.js
index e17201ac0..71f801a84 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -25,5 +25,17 @@ module.exports = {
         "eslint-plugin/test-case-shorthand-strings": "error",
         "rulesdir/multiline-comment-style": "error",
         "rulesdir/no-useless-catch": "error"
-    }
+    },
+    overrides: [
+        {
+            files: ["tests/**/*"],
+            env: { mocha: true },
+            rules: {
+                "no-restricted-syntax": ["error", {
+                    selector: "CallExpression[callee.object.name='assert'][callee.property.name='doesNotThrow']",
+                    message: "`assert.doesNotThrow()` should be replaced with a comment next to the code."
+                }]
+            }
+        }
+    ]
 };
diff --git a/README.md b/README.md
index 34fd0ef36..572cd8a07 100644
--- a/README.md
+++ b/README.md
@@ -157,7 +157,7 @@ Join our [Mailing List](https://groups.google.com/group/eslint) or [Chatroom](ht
 
 ## Releases
 
-We have scheduled releases every two weeks on Friday or Saturday.
+We have scheduled releases every two weeks on Friday or Saturday. You can follow a [release issue](https://github.com/eslint/eslint/issues?q=is%3Aopen+is%3Aissue+label%3Arelease) for updates about the scheduling of any particular release.
 
 ## Semantic Versioning Policy
 
diff --git a/lib/code-path-analysis/code-path-analyzer.js b/lib/code-path-analysis/code-path-analyzer.js
index 80b73faa3..f4a7fee7f 100644
--- a/lib/code-path-analysis/code-path-analyzer.js
+++ b/lib/code-path-analysis/code-path-analyzer.js
@@ -60,7 +60,7 @@ function isForkingByTrueOrFalse(node) {
             return parent.test === node;
 
         case "LogicalExpression":
-            return true;
+            return isHandledLogicalOperator(parent.operator);
 
         default:
             return false;
diff --git a/lib/config/config-validator.js b/lib/config/config-validator.js
index 185d4650d..6b151f46a 100644
--- a/lib/config/config-validator.js
+++ b/lib/config/config-validator.js
@@ -23,10 +23,15 @@ const ruleValidators = new WeakMap();
 let validateSchema;
 
 // Defitions for deprecation warnings.
-const deprecationWarningMessages = Object.freeze({
+const deprecationWarningMessages = {
     ESLINT_LEGACY_ECMAFEATURES: "The 'ecmaFeatures' config file property is deprecated, and has no effect.",
     ESLINT_LEGACY_OBJECT_REST_SPREAD: "The 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' option is deprecated. Use 'parserOptions.ecmaVersion' instead."
-});
+};
+const severityMap = {
+    error: 2,
+    warn: 1,
+    off: 0
+};
 
 /**
  * Gets a complete options schema for a rule.
@@ -65,12 +70,14 @@ function getRuleOptionsSchema(rule) {
  */
 function validateRuleSeverity(options) {
     const severity = Array.isArray(options) ? options[0] : options;
+    const normSeverity = typeof severity === "string" ? severityMap[severity.toLowerCase()] : severity;
 
-    if (severity !== 0 && severity !== 1 && severity !== 2 && !(typeof severity === "string" && /^(?:off|warn|error)$/i.test(severity))) {
-        throw new Error(`\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '${util.inspect(severity).replace(/'/g, "\"").replace(/\n/g, "")}').\n`);
+    if (normSeverity === 0 || normSeverity === 1 || normSeverity === 2) {
+        return normSeverity;
     }
 
-    return severity;
+    throw new Error(`\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '${util.inspect(severity).replace(/'/g, "\"").replace(/\n/g, "")}').\n`);
+
 }
 
 /**
@@ -116,7 +123,7 @@ function validateRuleOptions(rule, ruleId, options, source) {
     try {
         const severity = validateRuleSeverity(options);
 
-        if (severity !== 0 && !(typeof severity === "string" && severity.toLowerCase() === "off")) {
+        if (severity !== 0) {
             validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
         }
     } catch (err) {


Test patch:
diff --git a/tests/.eslintrc.yml b/tests/.eslintrc.yml
deleted file mode 100644
index f2531eaa4..000000000
--- a/tests/.eslintrc.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-env:
-  mocha: true
-
-rules:
-  no-restricted-syntax:
-    - error
-    - selector: "CallExpression[callee.object.name='assert'][callee.property.name='doesNotThrow']"
-      message: "`assert.doesNotThrow()` should be replaced with a comment next to the code."
diff --git a/tests/fixtures/parsers/unknown-operators/unknown-logical-operator-nested.js b/tests/fixtures/parsers/unknown-operators/unknown-logical-operator-nested.js
new file mode 100644
index 000000000..248480710
--- /dev/null
+++ b/tests/fixtures/parsers/unknown-operators/unknown-logical-operator-nested.js
@@ -0,0 +1,227 @@
+/**
+ * The output AST has been modified to represent an unknown operator
+ * (replaced ?? with %%)
+ *
+ * Parser: babel-eslint v8.2.3
+ * (with this fix for tokens: https://github.com/babel/babel-eslint/pull/632)
+ * Source code:
+ * foo && bar ?? baz
+ */
+
+exports.parse = () => ({
+    type: "Program",
+    start: 0,
+    end: 17,
+    loc: {
+        start: {
+            line: 1,
+            column: 0
+        },
+        end: {
+            line: 1,
+            column: 17
+        }
+    },
+    range: [0, 17],
+    comments: [],
+    tokens: [
+        {
+            type: "Identifier",
+            value: "foo",
+            start: 0,
+            end: 3,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 0
+                },
+                end: {
+                    line: 1,
+                    column: 3
+                }
+            },
+            range: [0, 3]
+        },
+        {
+            type: "Punctuator",
+            value: "&&",
+            start: 4,
+            end: 6,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 4
+                },
+                end: {
+                    line: 1,
+                    column: 6
+                }
+            },
+            range: [4, 6]
+        },
+        {
+            type: "Identifier",
+            value: "bar",
+            start: 7,
+            end: 10,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 7
+                },
+                end: {
+                    line: 1,
+                    column: 10
+                }
+            },
+            range: [7, 10]
+        },
+        {
+            type: "Punctuator",
+            value: "%%",
+            start: 11,
+            end: 13,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 11
+                },
+                end: {
+                    line: 1,
+                    column: 13
+                }
+            },
+            range: [11, 13]
+        },
+        {
+            type: "Identifier",
+            value: "baz",
+            start: 14,
+            end: 17,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 14
+                },
+                end: {
+                    line: 1,
+                    column: 17
+                }
+            },
+            range: [14, 17]
+        }
+    ],
+    sourceType: "module",
+    body: [
+        {
+            type: "ExpressionStatement",
+            start: 0,
+            end: 17,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 0
+                },
+                end: {
+                    line: 1,
+                    column: 17
+                }
+            },
+            range: [0, 17],
+            expression: {
+                type: "LogicalExpression",
+                start: 0,
+                end: 17,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 0
+                    },
+                    end: {
+                        line: 1,
+                        column: 17
+                    }
+                },
+                range: [0, 17],
+                left: {
+                    type: "LogicalExpression",
+                    start: 0,
+                    end: 10,
+                    loc: {
+                        start: {
+                            line: 1,
+                            column: 0
+                        },
+                        end: {
+                            line: 1,
+                            column: 10
+                        }
+                    },
+                    range: [0, 10],
+                    left: {
+                        type: "Identifier",
+                        start: 0,
+                        end: 3,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 0
+                            },
+                            end: {
+                                line: 1,
+                                column: 3
+                            },
+                            identifierName: "foo"
+                        },
+                        range: [0, 3],
+                        name: "foo",
+                        _babelType: "Identifier"
+                    },
+                    operator: "&&",
+                    right: {
+                        type: "Identifier",
+                        start: 7,
+                        end: 10,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 7
+                            },
+                            end: {
+                                line: 1,
+                                column: 10
+                            },
+                            identifierName: "bar"
+                        },
+                        range: [7, 10],
+                        name: "bar",
+                        _babelType: "Identifier"
+                    },
+                    _babelType: "LogicalExpression"
+                },
+                operator: "%%",
+                right: {
+                    type: "Identifier",
+                    start: 14,
+                    end: 17,
+                    loc: {
+                        start: {
+                            line: 1,
+                            column: 14
+                        },
+                        end: {
+                            line: 1,
+                            column: 17
+                        },
+                        identifierName: "baz"
+                    },
+                    range: [14, 17],
+                    name: "baz",
+                    _babelType: "Identifier"
+                },
+                _babelType: "LogicalExpression"
+            },
+            _babelType: "ExpressionStatement"
+        }
+    ]
+});
diff --git a/tests/lib/linter.js b/tests/lib/linter.js
index 251057021..e06f3cd9a 100644
--- a/tests/lib/linter.js
+++ b/tests/lib/linter.js
@@ -4480,6 +4480,16 @@ describe("Linter", () => {
                 assert.strictEqual(messages.length, 0);
             });
 
+            it("should not throw or report errors when the custom parser returns nested unrecognized operators (https://github.com/eslint/eslint/issues/10560)", () => {
+                const code = "foo && bar %% baz";
+                const parser = path.join(parserFixtures, "unknown-operators", "unknown-logical-operator-nested.js");
+
+                // This shouldn't throw
+                const messages = linter.verify(code, { parser }, filename, true);
+
+                assert.strictEqual(messages.length, 0);
+            });
+
             it("should strip leading line: prefix from parser error", () => {
                 const parser = path.join(parserFixtures, "line-error.js");
                 const messages = linter.verify(";", { parser }, "filename");
diff --git a/tests/lib/testers/no-test-runners.js b/tests/lib/testers/no-test-runners.js
index a14ac3bab..eac1da3fd 100644
--- a/tests/lib/testers/no-test-runners.js
+++ b/tests/lib/testers/no-test-runners.js
@@ -4,7 +4,6 @@
  */
 "use strict";
 
-/* global describe, it */
 /* eslint-disable no-global-assign*/
 const assert = require("assert");
 const RuleTester = require("../../../lib/testers/rule-tester");
diff --git a/tests/lib/testers/rule-tester.js b/tests/lib/testers/rule-tester.js
index 0a51dc26b..4265ab1b9 100644
--- a/tests/lib/testers/rule-tester.js
+++ b/tests/lib/testers/rule-tester.js
@@ -4,8 +4,6 @@
  */
 "use strict";
 
-/* global describe, it */
-
 //------------------------------------------------------------------------------
 // Requirements
 //------------------------------------------------------------------------------