Repository: eslint/eslint
Pull request #12054 (2019-08-02 20:31:49)

Docs: Remove TDZ scope from the scope manager interface documentation
<!--
    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] Documentation update

<!--
    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)**

Removed TDZ Scope type and TDZ Definition type from `scope-manager-interface.md`

**Is there anything you'd like reviewers to focus on?**


Patch:
diff --git a/README.md b/README.md
index ed485f66b..061eafefc 100644
--- a/README.md
+++ b/README.md
@@ -59,8 +59,6 @@ After that, you can run ESLint on any file or directory like this:
 $ ./node_modules/.bin/eslint yourfile.js
 ```
 
-It is also possible to install ESLint globally rather than locally (using `npm install eslint --global`). However, any plugins or shareable configs that you use must be installed locally in either case.
-
 ## <a name="configuration"></a>Configuration
 
 After running `eslint --init`, you'll have a `.eslintrc` file in your directory. In it, you'll see some rules configured like this:
@@ -260,7 +258,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
 <h3>Gold Sponsors</h3>
 <p><a href="https://www.shopify.com"><img src="https://images.opencollective.com/shopify/eeb91aa/logo.png" alt="Shopify" height="96"></a> <a href="http://salesforce.com"><img src="https://images.opencollective.com/salesforce/853ecef/logo.png" alt="Salesforce" height="96"></a> <a href="https://badoo.com/team?utm_source=eslint"><img src="https://images.opencollective.com/badoo/2826a3b/logo.png" alt="Badoo" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/001a341/logo.png" alt="Airbnb" height="96"></a> <a href="https://code.facebook.com/projects/"><img src="https://images.opencollective.com/fbopensource/fbb8a5b/logo.png" alt="Facebook Open Source" height="96"></a></p><h3>Silver Sponsors</h3>
 <p><a href="https://www.ampproject.org/"><img src="https://images.opencollective.com/amp/c8a3b25/logo.png" alt="AMP Project" height="64"></a></p><h3>Bronze Sponsors</h3>
-<p><a href="https://uxplanet.org/top-ui-ux-design-agencies-user-experience-firms-8c54697e290"><img src="https://images.opencollective.com/ux-top-5/cae5dfe/logo.png" alt="UX Top 5" height="32"></a> <a href="https://clay.global"><img src="https://images.opencollective.com/clayglobal/2468f34/logo.png" alt="clay" height="32"></a> <a href="https://discordapp.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://tekhattan.com"><img src="https://images.opencollective.com/tekhattan/bc73c28/logo.png" alt="TekHattan" height="32"></a> <a href="https://www.marfeel.com/"><img src="https://images.opencollective.com/marfeel/4b88e30/logo.png" alt="Marfeel" height="32"></a> <a href="http://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://jsheroes.io/"><img src="https://images.opencollective.com/jsheroes1/9fedf0b/logo.png" alt="JSHeroes " height="32"></a> <a href="https://faithlife.com/ref/about"><img src="https://images.opencollective.com/faithlife/534b832/logo.png" alt="Faithlife" height="32"></a></p>
+<p><a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/0b37d14/logo.png" alt="Free Icons by Icons8" height="32"></a> <a href="https://uxplanet.org/top-ui-ux-design-agencies-user-experience-firms-8c54697e290"><img src="https://images.opencollective.com/ui-ux-design-agencies/cae5dfe/logo.png" alt="UI UX Design Agencies" height="32"></a> <a href="https://clay.global"><img src="https://images.opencollective.com/clayglobal/2468f34/logo.png" alt="clay" height="32"></a> <a href="https://discordapp.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://tekhattan.com"><img src="https://images.opencollective.com/tekhattan/bc73c28/logo.png" alt="TekHattan" height="32"></a> <a href="https://www.marfeel.com/"><img src="https://images.opencollective.com/marfeel/4b88e30/logo.png" alt="Marfeel" height="32"></a> <a href="http://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://jsheroes.io/"><img src="https://images.opencollective.com/jsheroes1/9fedf0b/logo.png" alt="JSHeroes " height="32"></a> <a href="https://faithlife.com/ref/about"><img src="https://images.opencollective.com/faithlife/534b832/logo.png" alt="Faithlife" height="32"></a></p>
 <!--sponsorsend-->
 
 ## <a name="technology-sponsors"></a>Technology Sponsors
diff --git a/docs/developer-guide/scope-manager-interface.md b/docs/developer-guide/scope-manager-interface.md
index 08986caa2..3ee5b23d3 100644
--- a/docs/developer-guide/scope-manager-interface.md
+++ b/docs/developer-guide/scope-manager-interface.md
@@ -28,7 +28,7 @@ This document was written based on the implementation of [eslint-scope](https://
     * `node` (`ASTNode`) ... An AST node to get their scope.
     * `inner` (`boolean`) ... If the node has multiple scope, this returns the outermost scope normally. If `inner` is `true` then this returns the innermost scope. Default is `false`.
 * **Return type:** `Scope | null`
-* **Description:** Get the scope of a given AST node. The gotten scope's `block` property is the node. This method never returns `function-expression-name` scope and `TDZ` scope. If the node does not have their scope, this returns `null`.
+* **Description:** Get the scope of a given AST node. The gotten scope's `block` property is the node. This method never returns `function-expression-name` scope. If the node does not have their scope, this returns `null`.
 
 #### getDeclaredVariables(node)
 
@@ -77,7 +77,7 @@ Those members are defined but not used in ESLint.
 #### type
 
 * **Type:** `string`
-* **Description:** The type of this scope. This is one of `"block"`, `"catch"`, `"class"`, `"for"`, `"function"`, `"function-expression-name"`, `"global"`, `"module"`, `"switch"`, `"with"`, `"TDZ"`
+* **Description:** The type of this scope. This is one of `"block"`, `"catch"`, `"class"`, `"for"`, `"function"`, `"function-expression-name"`, `"global"`, `"module"`, `"switch"`, `"with"`
 
 #### isStrict
 
@@ -334,7 +334,7 @@ Those members are defined but not used in ESLint.
 #### type
 
 * **Type:** `string`
-* **Description:** The type of this definition. One of `"CatchClause"`, `"ClassName"`, `"FunctionName"`, `"ImplicitGlobalVariable"`, `"ImportBinding"`, `"Parameter"`, `"TDZ"`, and `"Variable"`.
+* **Description:** The type of this definition. One of `"CatchClause"`, `"ClassName"`, `"FunctionName"`, `"ImplicitGlobalVariable"`, `"ImportBinding"`, `"Parameter"`, and `"Variable"`.
 
 #### name
 
@@ -354,7 +354,6 @@ Those members are defined but not used in ESLint.
 | `"ImplicitGlobalVariable"` | `Program`
 | `"ImportBinding"`          | `ImportSpecifier`, `ImportDefaultSpecifier`, or `ImportNamespaceSpecifier`
 | `"Parameter"`              | `FunctionDeclaration`, `FunctionExpression`, or `ArrowFunctionExpression`
-| `"TDZ"`                    | ?
 | `"Variable"`               | `VariableDeclarator`
 
 #### parent
@@ -370,7 +369,6 @@ Those members are defined but not used in ESLint.
 | `"ImplicitGlobalVariable"` | `null`
 | `"ImportBinding"`          | `ImportDeclaration`
 | `"Parameter"`              | `null`
-| `"TDZ"`                    | `null`
 | `"Variable"`               | `VariableDeclaration`
 
 ### Deprecated members
diff --git a/docs/rules/no-mixed-operators.md b/docs/rules/no-mixed-operators.md
index 3c0bb2fab..3206d18fb 100644
--- a/docs/rules/no-mixed-operators.md
+++ b/docs/rules/no-mixed-operators.md
@@ -5,6 +5,8 @@ This rule warns when different operators are used consecutively without parenthe
 
 ```js
 var foo = a && b || c || d;    /*BAD: Unexpected mix of '&&' and '||'.*/
+var foo = a && b ? c : d;      /*BAD: Unexpected mix of '&&' and '?:'.*/
+var foo = (a && b) ? c : d;    /*GOOD*/
 var foo = (a && b) || c || d;  /*GOOD*/
 var foo = a && (b || c || d);  /*GOOD*/
 ```
@@ -23,10 +25,21 @@ will generate
 1:18  Unexpected mix of '&&' and '||'. (no-mixed-operators)
 ```
 
+```js
+var foo = a && b ? c : d;
+```
+
+will generate
+
+```sh
+1:13  Unexpected mix of '&&' and '?:'. (no-mixed-operators)
+1:18  Unexpected mix of '&&' and '?:'. (no-mixed-operators)
+```
+
 
 ## Rule Details
 
-This rule checks `BinaryExpression` and `LogicalExpression`.
+This rule checks `BinaryExpression`, `LogicalExpression` and `ConditionalExpression`.
 
 This rule may conflict with [no-extra-parens](no-extra-parens.md) rule.
 If you use both this and [no-extra-parens](no-extra-parens.md) rule together, you need to use the `nestedBinaryExpressions` option of [no-extra-parens](no-extra-parens.md) rule.
@@ -75,7 +88,8 @@ var foo = (a + b) * c;
 
 This rule has 2 options.
 
-* `groups` (`string[][]`) - specifies operator groups to be checked. The `groups` option is a list of groups, and a group is a list of binary operators. Default operator groups are defined as arithmetic, bitwise, comparison, logical, and relational operators.
+* `groups` (`string[][]`) - specifies operator groups to be checked. The `groups` option is a list of groups, and a group is a list of binary operators. Default operator groups are defined as arithmetic, bitwise, comparison, logical, and relational operators. Note: Ternary operator(?:) can be part of any group and by default is allowed to be mixed with other operators.
+
 * `allowSamePrecedence` (`boolean`) - specifies whether to allow mixed operators if they are of equal precedence. Default is `true`.
 
 ### groups
@@ -87,6 +101,7 @@ The following operators can be used in `groups` option:
 * Comparison Operators: `"=="`, `"!="`, `"==="`, `"!=="`, `">"`, `">="`, `"<"`, `"<="`
 * Logical Operators: `"&&"`, `"||"`
 * Relational Operators: `"in"`, `"instanceof"`
+* Ternary Operator: `?:`
 
 Now, consider the following group configuration: `{"groups": [["&", "|", "^", "~", "<<", ">>", ">>>"], ["&&", "||"]]}`.
 There are 2 groups specified in this configuration: bitwise operators and logical operators.
@@ -102,6 +117,12 @@ var foo = a && b < 0 || c > 0 || d + 1 === 0;
 var foo = a & b | c;
 ```
 
+```js
+/*eslint no-mixed-operators: ["error", {"groups": [["&&", "||", "?:"]]}]*/
+
+var foo = a || b ? c : d;
+```
+
 Examples of **correct** code for this rule with `{"groups": [["&", "|", "^", "~", "<<", ">>", ">>>"], ["&&", "||"]]}` option:
 
 ```js
@@ -118,6 +139,13 @@ var foo = a + (b * c);
 var foo = (a + b) * c;
 ```
 
+```js
+/*eslint no-mixed-operators: ["error", {"groups": [["&&", "||", "?:"]]}]*/
+
+var foo = (a || b) ? c : d;
+var foo = a || (b ? c : d);
+```
+
 ### allowSamePrecedence
 
 Examples of **correct** code for this rule with `{"allowSamePrecedence": true}` option:
diff --git a/docs/rules/no-undef.md b/docs/rules/no-undef.md
index f5dc5a280..faaf978cc 100644
--- a/docs/rules/no-undef.md
+++ b/docs/rules/no-undef.md
@@ -11,32 +11,25 @@ Examples of **incorrect** code for this rule:
 ```js
 /*eslint no-undef: "error"*/
 
-var a = someFunction();
-b = 10;
+var foo = someFunction();
+var bar = a + 1;
 ```
 
 Examples of **correct** code for this rule with `global` declaration:
 
 ```js
-/*global someFunction b:writable*/
+/*global someFunction, a*/
 /*eslint no-undef: "error"*/
 
-var a = someFunction();
-b = 10;
+var foo = someFunction();
+var bar = a + 1;
 ```
 
-The `b:writable` syntax in `/*global */` indicates that assignment to `b` is correct.
+Note that this rule does not disallow assignments to read-only global variables.
+See [no-global-assign](no-global-assign.md) if you also want to disallow those assignments.
 
-Examples of **incorrect** code for this rule with `global` declaration:
-
-```js
-/*global b*/
-/*eslint no-undef: "error"*/
-
-b = 10;
-```
-
-By default, variables declared in `/*global */` are read-only, therefore assignment is incorrect.
+This rule also does not disallow redeclarations of global variables.
+See [no-redeclare](no-redeclare.md) if you also want to disallow those redeclarations.
 
 ## Options
 
@@ -111,3 +104,8 @@ If explicit declaration of global variables is not to your taste.
 ## Compatibility
 
 This rule provides compatibility with treatment of global variables in [JSHint](http://jshint.com/) and [JSLint](http://www.jslint.com).
+
+## Related Rules
+
+* [no-global-assign](no-global-assign.md)
+* [no-redeclare](no-redeclare.md)
diff --git a/docs/user-guide/getting-started.md b/docs/user-guide/getting-started.md
index 45633f618..1bebf7d69 100644
--- a/docs/user-guide/getting-started.md
+++ b/docs/user-guide/getting-started.md
@@ -33,7 +33,7 @@ After that, you can run ESLint on any file or directory like this:
 $ ./node_modules/.bin/eslint yourfile.js
 ```
 
-It is also possible to install ESLint globally rather than locally (using `npm install eslint --global`). However, any plugins or shareable configs that you use must be installed locally in either case.
+It is also possible to install ESLint globally rather than locally (using `npm install eslint --global`). However, this is not recommended, and any plugins or shareable configs that you use must be installed locally in either case.
 
 ## Configuration
 
diff --git a/lib/rules/class-methods-use-this.js b/lib/rules/class-methods-use-this.js
index 0eb1da87f..c15f32e66 100644
--- a/lib/rules/class-methods-use-this.js
+++ b/lib/rules/class-methods-use-this.js
@@ -70,7 +70,8 @@ module.exports = {
          * @private
          */
         function isIncludedInstanceMethod(node) {
-            return isInstanceMethod(node) && !exceptMethods.has(node.key.name);
+            return isInstanceMethod(node) &&
+                (node.computed || !exceptMethods.has(node.key.name));
         }
 
         /**
diff --git a/lib/rules/no-extra-parens.js b/lib/rules/no-extra-parens.js
index 6c3198b5f..c9278f2d0 100644
--- a/lib/rules/no-extra-parens.js
+++ b/lib/rules/no-extra-parens.js
@@ -686,6 +686,13 @@ module.exports = {
 
             CallExpression: checkCallNew,
 
+            ClassBody(node) {
+                node.body
+                    .filter(member => member.type === "MethodDefinition" && member.computed &&
+                        member.key && hasExcessParens(member.key) && precedence(member.key) >= PRECEDENCE_OF_ASSIGNMENT_EXPR)
+                    .forEach(member => report(member.key));
+            },
+
             ConditionalExpression(node) {
                 if (isReturnAssignException(node)) {
                     return;
diff --git a/lib/rules/no-mixed-operators.js b/lib/rules/no-mixed-operators.js
index 21e1d95c6..8d1c7a6af 100644
--- a/lib/rules/no-mixed-operators.js
+++ b/lib/rules/no-mixed-operators.js
@@ -20,12 +20,14 @@ const BITWISE_OPERATORS = ["&", "|", "^", "~", "<<", ">>", ">>>"];
 const COMPARISON_OPERATORS = ["==", "!=", "===", "!==", ">", ">=", "<", "<="];
 const LOGICAL_OPERATORS = ["&&", "||"];
 const RELATIONAL_OPERATORS = ["in", "instanceof"];
+const TERNARY_OPERATOR = ["?:"];
 const ALL_OPERATORS = [].concat(
     ARITHMETIC_OPERATORS,
     BITWISE_OPERATORS,
     COMPARISON_OPERATORS,
     LOGICAL_OPERATORS,
-    RELATIONAL_OPERATORS
+    RELATIONAL_OPERATORS,
+    TERNARY_OPERATOR
 );
 const DEFAULT_GROUPS = [
     ARITHMETIC_OPERATORS,
@@ -34,7 +36,7 @@ const DEFAULT_GROUPS = [
     LOGICAL_OPERATORS,
     RELATIONAL_OPERATORS
 ];
-const TARGET_NODE_TYPE = /^(?:Binary|Logical)Expression$/u;
+const TARGET_NODE_TYPE = /^(?:Binary|Logical|Conditional)Expression$/u;
 
 /**
  * Normalizes options.
@@ -65,6 +67,18 @@ function includesBothInAGroup(groups, left, right) {
     return groups.some(group => group.indexOf(left) !== -1 && group.indexOf(right) !== -1);
 }
 
+/**
+ * Checks whether the given node is a conditional expression and returns the test node else the left node.
+ *
+ * @param {ASTNode} node - A node which can be a BinaryExpression or a LogicalExpression node.
+ * This parent node can be BinaryExpression, LogicalExpression
+ *      , or a ConditionalExpression node
+ * @returns {ASTNode} node the appropriate node(left or test).
+ */
+function getChildNode(node) {
+    return node.type === "ConditionalExpression" ? node.test : node.left;
+}
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -121,7 +135,7 @@ module.exports = {
             const b = node.parent;
 
             return (
-                !includesBothInAGroup(options.groups, a.operator, b.operator) ||
+                !includesBothInAGroup(options.groups, a.operator, b.type === "ConditionalExpression" ? "?:" : b.operator) ||
                 (
                     options.allowSamePrecedence &&
                     astUtils.getPrecedence(a) === astUtils.getPrecedence(b)
@@ -139,12 +153,25 @@ module.exports = {
          * @returns {boolean} `true` if the node was mixed.
          */
         function isMixedWithParent(node) {
+
             return (
                 node.operator !== node.parent.operator &&
                 !astUtils.isParenthesised(sourceCode, node)
             );
         }
 
+        /**
+         * Checks whether the operator of a given node is mixed with a
+         * conditional expression.
+         *
+         * @param {ASTNode} node - A node to check. This is a conditional
+         *      expression node
+         * @returns {boolean} `true` if the node was mixed.
+         */
+        function isMixedWithConditionalParent(node) {
+            return !astUtils.isParenthesised(sourceCode, node) && !astUtils.isParenthesised(sourceCode, node.test);
+        }
+
         /**
          * Gets the operator token of a given node.
          *
@@ -153,7 +180,7 @@ module.exports = {
          * @returns {Token} The operator token of the node.
          */
         function getOperatorToken(node) {
-            return sourceCode.getTokenAfter(node.left, astUtils.isNotClosingParenToken);
+            return sourceCode.getTokenAfter(getChildNode(node), astUtils.isNotClosingParenToken);
         }
 
         /**
@@ -167,13 +194,13 @@ module.exports = {
          */
         function reportBothOperators(node) {
             const parent = node.parent;
-            const left = (parent.left === node) ? node : parent;
-            const right = (parent.left !== node) ? node : parent;
+            const left = (getChildNode(parent) === node) ? node : parent;
+            const right = (getChildNode(parent) !== node) ? node : parent;
             const message =
                 "Unexpected mix of '{{leftOperator}}' and '{{rightOperator}}'.";
             const data = {
-                leftOperator: left.operator,
-                rightOperator: right.operator
+                leftOperator: left.operator || "?:",
+                rightOperator: right.operator || "?:"
             };
 
             context.report({
@@ -198,17 +225,25 @@ module.exports = {
          * @returns {void}
          */
         function check(node) {
-            if (TARGET_NODE_TYPE.test(node.parent.type) &&
-                isMixedWithParent(node) &&
-                !shouldIgnore(node)
-            ) {
-                reportBothOperators(node);
+            if (TARGET_NODE_TYPE.test(node.parent.type)) {
+                if (node.parent.type === "ConditionalExpression" && !shouldIgnore(node) && isMixedWithConditionalParent(node.parent)) {
+                    reportBothOperators(node);
+                } else {
+                    if (TARGET_NODE_TYPE.test(node.parent.type) &&
+                        isMixedWithParent(node) &&
+                        !shouldIgnore(node)
+                    ) {
+                        reportBothOperators(node);
+                    }
+                }
             }
+
         }
 
         return {
             BinaryExpression: check,
             LogicalExpression: check
+
         };
     }
 };
diff --git a/lib/rules/no-restricted-syntax.js b/lib/rules/no-restricted-syntax.js
index 74eea1478..41aa9fa39 100644
--- a/lib/rules/no-restricted-syntax.js
+++ b/lib/rules/no-restricted-syntax.js
@@ -21,7 +21,7 @@ module.exports = {
 
         schema: {
             type: "array",
-            items: [{
+            items: {
                 oneOf: [
                     {
                         type: "string"
@@ -36,7 +36,7 @@ module.exports = {
                         additionalProperties: false
                     }
                 ]
-            }],
+            },
             uniqueItems: true,
             minItems: 0
         }


Test patch:
diff --git a/tests/lib/rules/class-methods-use-this.js b/tests/lib/rules/class-methods-use-this.js
index 852124245..89af434fd 100644
--- a/tests/lib/rules/class-methods-use-this.js
+++ b/tests/lib/rules/class-methods-use-this.js
@@ -97,6 +97,14 @@ ruleTester.run("class-methods-use-this", rule, {
             errors: [
                 { type: "FunctionExpression", line: 1, column: 34, messageId: "missingThis", data: { name: "hasOwnProperty" } }
             ]
+        },
+        {
+            code: "class A { [foo]() {} }",
+            options: [{ exceptMethods: ["foo"] }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { type: "FunctionExpression", line: 1, column: 16, messageId: "missingThis", data: { name: "foo" } }
+            ]
         }
     ]
 });
diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js
index 7be7d6e9e..6c6eeb2a1 100644
--- a/tests/lib/rules/no-extra-parens.js
+++ b/tests/lib/rules/no-extra-parens.js
@@ -160,6 +160,13 @@ ruleTester.run("no-extra-parens", rule, {
         "const {[a]:b=1} = {}",
         "const {[(a, b)]:c} = {}",
         "const {a, ...b} = {}",
+        "class foo {}",
+        "class foo { constructor(){} a(){} get b(){} set b(bar){} get c(){} set d(baz){} static e(){} }",
+        "class foo { [a](){} get [b](){} set [b](bar){} get [c](){} set [d](baz){} static [e](){} }",
+        "class foo { [(a,b)](){} }",
+        "class foo { a(){} [b](){} c(){} [(d,e)](){} }",
+        "class foo { [(a,b)](){} c(){} [d](){} e(){} }",
+        "const foo = class { constructor(){} a(){} get b(){} set b(bar){} get c(){} set d(baz){} static e(){} }",
 
         // ExpressionStatement restricted productions
         "({});",
@@ -553,6 +560,22 @@ ruleTester.run("no-extra-parens", rule, {
         invalid("const {a, b:c, [(d+e)]:f, [(g,h)]:i, [j]:k} = {}", "const {a, b:c, [d+e]:f, [(g,h)]:i, [j]:k} = {}", "BinaryExpression", 1),
         invalid("const {[a+(b*c)]:d} = {}", "const {[a+b*c]:d} = {}", "BinaryExpression", 1),
         invalid("const {[(a, (b+c))]:d} = {}", "const {[(a, b+c)]:d} = {}", "BinaryExpression", 1),
+        invalid("class foo { [(a)](){} }", "class foo { [a](){} }", "Identifier"),
+        invalid("class foo {*[(Symbol.iterator)]() {}}", "class foo {*[Symbol.iterator]() {}}", "MemberExpression"),
+        invalid("class foo { get [(a)](){} }", "class foo { get [a](){} }", "Identifier"),
+        invalid("class foo { set [(a)](bar){} }", "class foo { set [a](bar){} }", "Identifier"),
+        invalid("class foo { static [(a)](bar){} }", "class foo { static [a](bar){} }", "Identifier"),
+        invalid("class foo { [(a=b)](){} }", "class foo { [a=b](){} }", "AssignmentExpression"),
+        invalid("class foo { constructor (){} [(a+b)](){} }", "class foo { constructor (){} [a+b](){} }", "BinaryExpression"),
+        invalid("class foo { [(a+b)](){} constructor (){} }", "class foo { [a+b](){} constructor (){} }", "BinaryExpression"),
+        invalid("class foo { [(a+b)](){} c(){} }", "class foo { [a+b](){} c(){} }", "BinaryExpression"),
+        invalid("class foo { a(){} [(b+c)](){} d(){} }", "class foo { a(){} [b+c](){} d(){} }", "BinaryExpression"),
+        invalid("class foo { [(a+b)](){} [c](){} }", "class foo { [a+b](){} [c](){} }", "BinaryExpression"),
+        invalid("class foo { [a](){} [(b+c)](){} [d](){} }", "class foo { [a](){} [b+c](){} [d](){} }", "BinaryExpression"),
+        invalid("class foo { [(a+b)](){} [(c,d)](){} }", "class foo { [a+b](){} [(c,d)](){} }", "BinaryExpression"),
+        invalid("class foo { [(a,b)](){} [(c+d)](){} }", "class foo { [(a,b)](){} [c+d](){} }", "BinaryExpression"),
+        invalid("class foo { [a+(b*c)](){} }", "class foo { [a+b*c](){} }", "BinaryExpression"),
+        invalid("const foo = class { [(a)](){} }", "const foo = class { [a](){} }", "Identifier"),
         invalid(
             "var foo = (function*() { if ((yield foo())) { return; } }())",
             "var foo = (function*() { if (yield foo()) { return; } }())",
diff --git a/tests/lib/rules/no-mixed-operators.js b/tests/lib/rules/no-mixed-operators.js
index d740b8562..4e822181f 100644
--- a/tests/lib/rules/no-mixed-operators.js
+++ b/tests/lib/rules/no-mixed-operators.js
@@ -47,7 +47,18 @@ ruleTester.run("no-mixed-operators", rule, {
         {
             code: "a * b / c",
             options: [{ allowSamePrecedence: true }]
-        }
+        },
+        {
+            code: "(a || b) ? c : d",
+            options: [{ groups: [["&&", "||", "?:"]] }]
+        },
+        {
+            code: "a || (b ? c : d)",
+            options: [{ groups: [["&&", "||", "?:"]] }]
+        },
+        "a || (b ? c : d)",
+        "(a || b) ? c : d",
+        "a || b ? c : d"
     ],
     invalid: [
         {
@@ -110,6 +121,38 @@ ruleTester.run("no-mixed-operators", rule, {
                 { column: 3, message: "Unexpected mix of '*' and '/'." },
                 { column: 7, message: "Unexpected mix of '*' and '/'." }
             ]
+        },
+        {
+            code: "a || b ? c : d",
+            options: [{ groups: [["&&", "||", "?:"]] }],
+            errors: [
+                { column: 3, message: "Unexpected mix of '||' and '?:'." },
+                { column: 8, message: "Unexpected mix of '||' and '?:'." }
+            ]
+        },
+        {
+            code: "a && b ? 1 : 2",
+            options: [{ groups: [["&&", "||", "?:"]] }],
+            errors: [
+                { column: 3, message: "Unexpected mix of '&&' and '?:'." },
+                { column: 8, message: "Unexpected mix of '&&' and '?:'." }
+            ]
+        },
+        {
+            code: "x ? a && b : 0",
+            options: [{ groups: [["&&", "||", "?:"]] }],
+            errors: [
+                { column: 3, message: "Unexpected mix of '?:' and '&&'." },
+                { column: 7, message: "Unexpected mix of '?:' and '&&'." }
+            ]
+        },
+        {
+            code: "x ? 0 : a && b",
+            options: [{ groups: [["&&", "||", "?:"]] }],
+            errors: [
+                { column: 3, message: "Unexpected mix of '?:' and '&&'." },
+                { column: 11, message: "Unexpected mix of '?:' and '&&'." }
+            ]
         }
     ]
 });