Repository: eslint/eslint
Pull request #8239 (2017-03-13 00:06:23)

Breaking: Remove `ecmaFeatures` from `eslint:recommended`
**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
[ ] Add something to the core
[X] Other, please explain:

**What changes did you make? (Give an overview)**
Remove `ecmaFeatures` from `eslint:recommended`. It's not a top level property since eslint v2.0.0.


**Is there anything you'd like reviewers to focus on?**
Should be tagged: 'Chore'? Not sure, since it's not really internal.
Even if it changes `eslint:recommended` I don't think it should be considered a breaking change.



eslintbot: LGTM
mention-bot: @alberto, thanks for your PR! By analyzing the history of the files in this pull request, we identified @nzakas, @platinumazure and @kaicataldo to be potential reviewers.
not-an-aardvark: Are there any scenarios where this change could cause errors? For example, could this cause a rule to crash if it's expecting `ecmaFeatures` to be present in the config?
alberto: I guess it could cause errors if it was assuming the existence of the property, not doing something like:

```
const ecmaFeatures = context.ecmaFeatures || {};

if ecmaFeatures.globalReturn) {...};
```

But then it would be checking against the wrong property, so the rule wouldn't be working as intended.
eslintbot: LGTM
platinumazure: I'd feel better if we just did this with 4.0 release "just in case" (IMO, it is making a potentially breaking alteration on a public API and we'd be honoring the semver contract). But I agree that the change "should" be harmless.
platinumazure: Added "breaking" label for now, per this excerpt from the [maintainer guide](http://eslint.org/docs/maintainer-guide/issues.html#when-an-issue-is-opened):

> Breaking Changes: if you **suspect** or can verify that a change would be breaking, label it as “Breaking”.

Emphasis mine. I'd like it discussed and if consensus is that the change is non-breaking, awesome, we can remove the label and merge as a chore.
platinumazure: Just to move this along (since I helped get it stuck in the first place), I'm going to add this to TSC agenda.

**TSC Summary**: The `eslint:recommended` should no longer export `ecmaFeatures` in its `parserOptions`, since that has been deprecated by espree long ago. The purpose of this PR is to remove `ecmaFeatures`. However, a concern was raised that any custom or plugin rules may rely on `context.ecmaFeatures` which could trip people up who are using `eslint:recommended` without being aware of this. I (platinumazure) labeled this as a potentially breaking change, with the idea that if the team disagrees, the label can be removed and this could be labeled as a chore.

**TSC Question**: Should this change be merged only with a major release, or can we safely merge it as a chore?
not-an-aardvark: This was accepted by the TSC as a breaking change in today's TSC meeting.
eslintbot: LGTM
eslintbot: LGTM

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 856d960eb..4f4b3bbdb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,42 @@
+v3.19.0 - March 31, 2017
+
+* e09132f Fix: no-extra-parens false positive with exports and object literals (#8359) (Teddy Katz)
+* 91baed4 Update: allow custom messages in no-restricted-syntax (fixes #8298) (#8357) (Vitor Balocco)
+* 35c93e6 Fix: prevent space-before-function-paren from checking type annotations (#8349) (Teddy Katz)
+* 3342e9f Fix: don't modify operator precedence in operator-assignment autofixer (#8358) (Teddy Katz)
+* f88375f Docs: clarify that no-unsafe-negation is in eslint:recommended (#8371) (Teddy Katz)
+* 02f0d27 Docs: Add soda0289 to Development Team (#8367) (Kai Cataldo)
+* 155424c Fix: ignore empty path in patterns (fixes #8362) (#8364) (alberto)
+* 27616a8 Fix: prefer-const false positive with object spread (fixes #8187) (#8297) (Vitor Balocco)
+* 8569a90 Docs: add note about git's linebreak handling to linebreak-style docs (#8361) (Teddy Katz)
+* 5878593 Chore: fix invalid syntax in no-param-reassign test (#8360) (Teddy Katz)
+* 1b1046b Fix: don't classify plugins that throw errors as "missing" (fixes #6874) (#8323) (Teddy Katz)
+* 29f4ba5 Fix: no-useless-computed-key invalid autofix for getters and setters (#8335) (Teddy Katz)
+* 0541eaf Fix: no-implicit-coercion invalid autofix with consecutive identifiers (#8340) (Teddy Katz)
+* 41b9786 Fix: no-extra-parens false positive with objects following arrows (#8339) (Teddy Katz)
+* 3146167 Fix: `eslint.verify` should not mutate config argument (fixes #8329) (#8334) (alberto)
+* 927de90 Fix: dot-notation autofix produces invalid syntax for integer properties (#8332) (Teddy Katz)
+* a9d1bea Fix: comma-style autofix produces errors on parenthesized elements (#8331) (Teddy Katz)
+* d52173f Fix: don't generate invalid options in config-rule (#8326) (Teddy Katz)
+* 6eda3b5 Fix: no-extra-parens invalid autofix in for-of statements (#8337) (Teddy Katz)
+* 6c819d8 Fix: dot-notation autofix produces errors on parenthesized computed keys (#8330) (Teddy Katz)
+* 2d883d7 Fix: object-shorthand autofix produces errors on parenthesized functions (#8328) (Teddy Katz)
+* cd9b774 Fix: quotes false positive with backtick option in method names (#8327) (Teddy Katz)
+* d064ba2 Fix: no-else-return false positive for ifs in single-statement position (#8338) (Teddy Katz)
+* 6a718ba Chore: enable max-statements-per-line on ESLint codebase (#8321) (Teddy Katz)
+* 614b62e Chore: update sinon calls to deprecated API. (#8310) (alberto)
+* 0491572 Chore: use precalculated counts in codeframe formatter (#8296) (Vitor Balocco)
+* 8733e6a Chore: Fix incorrect error location properties in tests (#8307) (alberto)
+* c4ffb49 Chore: Fix typos in test option assertions (#8305) (Teddy Katz)
+* 79a97cb Upgrade: devDependencies (#8303) (alberto)
+* e4da200 Upgrade: Mocha to 3.2.0 (#8299) (Ilya Volodin)
+* 2f144ca Fix: operator-assignment autofix errors with parentheses (fixes #8293) (#8294) (Teddy Katz)
+* 7521cd5 Chore: update token logic in rules to use ast-utils (#8288) (Teddy Katz)
+* 9b509ce Chore: refactor space-before-function-paren rule (#8284) (Teddy Katz)
+* ddc6350 Fix: no-param-reassign false positive on destructuring (fixes #8279) (#8281) (Teddy Katz)
+* f8176b3 Chore: improve test coverage for node-event-generator (#8287) (Teddy Katz)
+* 602e9c2 Docs: fix incorrect selector examples (#8278) (Teddy Katz)
+
 v3.18.0 - March 17, 2017
 
 * 85f74ca Fix: broken code path of direct nested loops (fixes #8248) (#8274) (Toru Nagashima)
diff --git a/Makefile.js b/Makefile.js
index 60f02b58c..0917a96b3 100644
--- a/Makefile.js
+++ b/Makefile.js
@@ -767,7 +767,7 @@ target.browserify = function() {
     generateRulesIndex(TEMP_DIR);
 
     // 5. browserify the temp directory
-    nodeCLI.exec("browserify", "-x espree", `${TEMP_DIR}eslint.js`, "-o", `${BUILD_DIR}eslint.js`, "-s eslint", "-t [ babelify --presets [ es2015 ] ]");
+    nodeCLI.exec("browserify", "-x espree", `${TEMP_DIR}eslint.js`, "-o", `${BUILD_DIR}eslint.js`, "-s eslint", "--global-transform [ babelify --presets [ es2015 ] ]");
 
     // 6. Browserify espree
     nodeCLI.exec("browserify", "-r espree", "-o", `${TEMP_DIR}espree.js`);
diff --git a/README.md b/README.md
index a08f276fc..1ccdbb9bf 100644
--- a/README.md
+++ b/README.md
@@ -130,6 +130,7 @@ These folks keep the project moving and are resources for help.
 * Kevin Partington ([@platinumazure](https://github.com/platinumazure))
 * Vitor Balocco ([@vitorbal](https://github.com/vitorbal))
 * James Henry ([@JamesHenry](https://github.com/JamesHenry))
+* Reyad Attiyat ([@soda0289](https://github.com/soda0289))
 
 ## Releases
 
diff --git a/conf/eslint-recommended.js b/conf/eslint-recommended.js
index 63c2fc770..70e395210 100755
--- a/conf/eslint-recommended.js
+++ b/conf/eslint-recommended.js
@@ -11,7 +11,6 @@
 
 module.exports = {
     parser: "espree",
-    ecmaFeatures: {},
 
     rules: {
 
diff --git a/docs/rules/no-restricted-syntax.md b/docs/rules/no-restricted-syntax.md
index ffe763c8b..8efbd780e 100644
--- a/docs/rules/no-restricted-syntax.md
+++ b/docs/rules/no-restricted-syntax.md
@@ -12,7 +12,7 @@ This rule disallows specified (that is, user-defined) syntax.
 
 ## Options
 
-This rule takes a list of strings:
+This rule takes a list of strings, where each string is an AST selector:
 
 ```json
 {
@@ -22,6 +22,30 @@ This rule takes a list of strings:
 }
 ```
 
+Alternatively, the rule also accepts objects, where the selector and an optional custom message are specified:
+
+```json
+{
+    "rules": {
+        "no-restricted-syntax": [
+            "error",
+            {
+                "selector": "FunctionExpression",
+                "message": "Function expressions are not allowed."
+            },
+            {
+                "selector": "CallExpression[callee.name='setTimeout'][arguments.length!=2]",
+                "message": "setTimeout must always be invoked with two arguments."
+            }
+        ]
+    }
+}
+```
+
+If a custom message is specified with the `message` property, ESLint will use that message when reporting occurrences of the syntax specified in the `selector` property.
+
+The string and object formats can be freely mixed in the configuration as needed.
+
 Examples of **incorrect** code for this rule with the `"FunctionExpression", "WithStatement", BinaryExpression[operator='in']` options:
 
 ```js
diff --git a/lib/ast-utils.js b/lib/ast-utils.js
index 0f2f3d6af..978f19ad2 100644
--- a/lib/ast-utils.js
+++ b/lib/ast-utils.js
@@ -556,9 +556,9 @@ module.exports = {
     /**
      * Finds the variable by a given name in a given scope and its upper scopes.
      *
-     * @param {escope.Scope} initScope - A scope to start find.
+     * @param {eslint-scope.Scope} initScope - A scope to start find.
      * @param {string} name - A variable name to find.
-     * @returns {escope.Variable|null} A found variable or `null`.
+     * @returns {eslint-scope.Variable|null} A found variable or `null`.
      */
     getVariableByName(initScope, name) {
         let scope = initScope;
diff --git a/lib/config/plugins.js b/lib/config/plugins.js
index e28a77929..aebb3669f 100644
--- a/lib/config/plugins.js
+++ b/lib/config/plugins.js
@@ -75,12 +75,6 @@ module.exports = {
         plugins[shortName] = plugin;
         Environments.importPlugin(plugin, shortName);
         Rules.importPlugin(plugin, shortName);
-
-        // load up environments and rules for the name that '@scope/' was omitted
-        // 3 lines below will be removed by 4.0.0
-        plugins[pluginNameWithoutPrefix] = plugin;
-        Environments.importPlugin(plugin, pluginNameWithoutPrefix);
-        Rules.importPlugin(plugin, pluginNameWithoutPrefix);
     },
 
     /**
diff --git a/lib/eslint.js b/lib/eslint.js
index a9066c4c8..1d8468235 100755
--- a/lib/eslint.js
+++ b/lib/eslint.js
@@ -11,7 +11,7 @@
 
 const assert = require("assert"),
     EventEmitter = require("events").EventEmitter,
-    escope = require("escope"),
+    eslintScope = require("eslint-scope"),
     levn = require("levn"),
     blankScriptAST = require("../conf/blank-script.json"),
     DEFAULT_PARSER = require("../conf/eslint-recommended").parser,
@@ -187,7 +187,7 @@ function addDeclaredGlobals(program, globalScope, config) {
         let variable = globalScope.set.get(name);
 
         if (!variable) {
-            variable = new escope.Variable(name, globalScope);
+            variable = new eslintScope.Variable(name, globalScope);
             variable.eslintExplicitGlobal = false;
             globalScope.variables.push(variable);
             globalScope.set.set(name, variable);
@@ -199,7 +199,7 @@ function addDeclaredGlobals(program, globalScope, config) {
         let variable = globalScope.set.get(name);
 
         if (!variable) {
-            variable = new escope.Variable(name, globalScope);
+            variable = new eslintScope.Variable(name, globalScope);
             variable.eslintExplicitGlobal = true;
             variable.eslintExplicitGlobalComment = explicitGlobals[name].comment;
             globalScope.variables.push(variable);
@@ -889,7 +889,7 @@ module.exports = (function() {
             const ecmaVersion = currentConfig.parserOptions.ecmaVersion || 5;
 
             // gather scope data that may be needed by the rules
-            scopeManager = escope.analyze(ast, {
+            scopeManager = eslintScope.analyze(ast, {
                 ignoreEval: true,
                 nodejsScope: ecmaFeatures.globalReturn,
                 impliedStrict: ecmaFeatures.impliedStrict,
@@ -1223,7 +1223,7 @@ module.exports = (function() {
      * - others - always an empty array.
      *
      * @param {ASTNode} node A node to get.
-     * @returns {escope.Variable[]} Variables that are declared by the node.
+     * @returns {eslint-scope.Variable[]} Variables that are declared by the node.
      */
     api.getDeclaredVariables = function(node) {
         return (scopeManager && scopeManager.getDeclaredVariables(node)) || [];
diff --git a/lib/rules/block-scoped-var.js b/lib/rules/block-scoped-var.js
index bb0931a3c..0b4d855fa 100644
--- a/lib/rules/block-scoped-var.js
+++ b/lib/rules/block-scoped-var.js
@@ -41,7 +41,7 @@ module.exports = {
 
         /**
          * Reports a given reference.
-         * @param {escope.Reference} reference - A reference to report.
+         * @param {eslint-scope.Reference} reference - A reference to report.
          * @returns {void}
          */
         function report(reference) {
diff --git a/lib/rules/func-names.js b/lib/rules/func-names.js
index e7f950c9b..848ce9757 100644
--- a/lib/rules/func-names.js
+++ b/lib/rules/func-names.js
@@ -13,7 +13,7 @@ const astUtils = require("../ast-utils");
 
 /**
  * Checks whether or not a given variable is a function name.
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is a function name.
  */
 function isFunctionName(variable) {
diff --git a/lib/rules/global-require.js b/lib/rules/global-require.js
index 367fe590e..beda8d99f 100644
--- a/lib/rules/global-require.js
+++ b/lib/rules/global-require.js
@@ -17,7 +17,7 @@ const ACCEPTABLE_PARENTS = [
 ];
 
 /**
- * Finds the escope reference in the given scope.
+ * Finds the eslint-scope reference in the given scope.
  * @param {Object} scope The scope to search.
  * @param {ASTNode} node The identifier node.
  * @returns {Reference|null} Returns the found reference or null if none were found.
diff --git a/lib/rules/no-alert.js b/lib/rules/no-alert.js
index f2cfc3a87..232fa1444 100644
--- a/lib/rules/no-alert.js
+++ b/lib/rules/no-alert.js
@@ -35,7 +35,7 @@ function report(context, node, identifierName) {
 }
 
 /**
- * Finds the escope reference in the given scope.
+ * Finds the eslint-scope reference in the given scope.
  * @param {Object} scope The scope to search.
  * @param {ASTNode} node The identifier node.
  * @returns {Reference|null} Returns the found reference or null if none were found.
diff --git a/lib/rules/no-console.js b/lib/rules/no-console.js
index 9131a49a0..32bdf6d1f 100644
--- a/lib/rules/no-console.js
+++ b/lib/rules/no-console.js
@@ -48,7 +48,7 @@ module.exports = {
         /**
          * Checks whether the given reference is 'console' or not.
          *
-         * @param {escope.Reference} reference - The reference to check.
+         * @param {eslint-scope.Reference} reference - The reference to check.
          * @returns {boolean} `true` if the reference is 'console'.
          */
         function isConsole(reference) {
@@ -74,7 +74,7 @@ module.exports = {
          * Checks whether the given reference is a member access which is not
          * allowed by options or not.
          *
-         * @param {escope.Reference} reference - The reference to check.
+         * @param {eslint-scope.Reference} reference - The reference to check.
          * @returns {boolean} `true` if the reference is a member access which
          *      is not allowed by options.
          */
@@ -92,7 +92,7 @@ module.exports = {
         /**
          * Reports the given reference as a violation.
          *
-         * @param {escope.Reference} reference - The reference to report.
+         * @param {eslint-scope.Reference} reference - The reference to report.
          * @returns {void}
          */
         function report(reference) {
diff --git a/lib/rules/no-dupe-args.js b/lib/rules/no-dupe-args.js
index cdb38035c..c932be01d 100644
--- a/lib/rules/no-dupe-args.js
+++ b/lib/rules/no-dupe-args.js
@@ -28,7 +28,7 @@ module.exports = {
 
         /**
          * Checks whether or not a given definition is a parameter's.
-         * @param {escope.DefEntry} def - A definition to check.
+         * @param {eslint-scope.DefEntry} def - A definition to check.
          * @returns {boolean} `true` if the definition is a parameter's.
          */
         function isParameter(def) {
diff --git a/lib/rules/no-eval.js b/lib/rules/no-eval.js
index fe1456cba..ee5f577f4 100644
--- a/lib/rules/no-eval.js
+++ b/lib/rules/no-eval.js
@@ -166,7 +166,7 @@ module.exports = {
         /**
          * Reports accesses of `eval` via the global object.
          *
-         * @param {escope.Scope} globalScope - The global scope.
+         * @param {eslint-scope.Scope} globalScope - The global scope.
          * @returns {void}
          */
         function reportAccessingEvalViaGlobalObject(globalScope) {
@@ -200,7 +200,7 @@ module.exports = {
         /**
          * Reports all accesses of `eval` (excludes direct calls to eval).
          *
-         * @param {escope.Scope} globalScope - The global scope.
+         * @param {eslint-scope.Scope} globalScope - The global scope.
          * @returns {void}
          */
         function reportAccessingEval(globalScope) {
diff --git a/lib/rules/no-extra-parens.js b/lib/rules/no-extra-parens.js
index 42a86484b..bbfae735c 100644
--- a/lib/rules/no-extra-parens.js
+++ b/lib/rules/no-extra-parens.js
@@ -60,6 +60,7 @@ module.exports = {
     create(context) {
         const sourceCode = context.getSourceCode();
 
+        const tokensToIgnore = new WeakSet();
         const isParenthesised = astUtils.isParenthesised.bind(astUtils, sourceCode);
         const precedence = astUtils.getPrecedence;
         const ALL_NODES = context.options[0] !== "functions";
@@ -238,69 +239,6 @@ module.exports = {
             return hasDoubleExcessParens(node);
         }
 
-        /**
-         * Checks whether or not a given node is located at the head of ExpressionStatement.
-         * @param {ASTNode} node - A node to check.
-         * @returns {boolean} `true` if the node is located at the head of ExpressionStatement.
-         */
-        function isHeadOfExpressionStatement(node) {
-            let parent = node.parent;
-
-            while (parent) {
-                switch (parent.type) {
-                    case "SequenceExpression":
-                        if (parent.expressions[0] !== node || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "UnaryExpression":
-                    case "UpdateExpression":
-                        if (parent.prefix || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "BinaryExpression":
-                    case "LogicalExpression":
-                        if (parent.left !== node || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "ConditionalExpression":
-                        if (parent.test !== node || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "CallExpression":
-                        if (parent.callee !== node || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "MemberExpression":
-                        if (parent.object !== node || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "ExpressionStatement":
-                        return true;
-
-                    default:
-                        return false;
-                }
-
-                node = parent;
-                parent = parent.parent;
-            }
-
-            /* istanbul ignore next */
-            throw new Error("unreachable");
-        }
-
         /**
          * Determines whether a node should be preceded by an additional space when removing parens
          * @param {ASTNode} node node to evaluate; must be surrounded by parentheses
@@ -345,9 +283,8 @@ module.exports = {
         function report(node) {
             const leftParenToken = sourceCode.getTokenBefore(node);
             const rightParenToken = sourceCode.getTokenAfter(node);
-            const tokenBeforeLeftParen = sourceCode.getTokenBefore(leftParenToken);
 
-            if (tokenBeforeLeftParen && astUtils.isArrowToken(tokenBeforeLeftParen) && astUtils.isOpeningBraceToken(sourceCode.getFirstToken(node))) {
+            if (tokensToIgnore.has(sourceCode.getFirstToken(node)) && !isParenthesisedTwice(node)) {
                 return;
             }
 
@@ -471,6 +408,34 @@ module.exports = {
             }
         }
 
+        /**
+         * Checks the parentheses for an ExpressionStatement or ExportDefaultDeclaration
+         * @param {ASTNode} node The ExpressionStatement.expression or ExportDefaultDeclaration.declaration node
+         * @returns {void}
+         */
+        function checkExpressionOrExportStatement(node) {
+            const firstToken = isParenthesised(node) ? sourceCode.getTokenBefore(node) : sourceCode.getFirstToken(node);
+            const secondToken = sourceCode.getTokenAfter(firstToken, astUtils.isNotOpeningParenToken);
+
+            if (
+                astUtils.isOpeningParenToken(firstToken) &&
+                (
+                    astUtils.isOpeningBraceToken(secondToken) ||
+                    secondToken.type === "Keyword" && (
+                        secondToken.value === "function" ||
+                        secondToken.value === "class" ||
+                        secondToken.value === "let" && astUtils.isOpeningBracketToken(sourceCode.getTokenAfter(secondToken))
+                    )
+                )
+            ) {
+                tokensToIgnore.add(secondToken);
+            }
+
+            if (hasExcessParens(node)) {
+                report(node);
+            }
+        }
+
         return {
             ArrayExpression(node) {
                 [].forEach.call(node.elements, e => {
@@ -486,13 +451,13 @@ module.exports = {
                 }
 
                 if (node.body.type !== "BlockStatement") {
-                    if (hasExcessParens(node.body) && precedence(node.body) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
-                        report(node.body);
-                        return;
-                    }
+                    const firstBodyToken = sourceCode.getFirstToken(node.body, astUtils.isNotOpeningParenToken);
+                    const tokenBeforeFirst = sourceCode.getTokenBefore(firstBodyToken);
 
-                    // Object literals *must* be parenthesised
-                    if (node.body.type === "ObjectExpression" && hasDoubleExcessParens(node.body)) {
+                    if (astUtils.isOpeningParenToken(tokenBeforeFirst) && astUtils.isOpeningBraceToken(firstBodyToken)) {
+                        tokensToIgnore.add(firstBodyToken);
+                    }
+                    if (hasExcessParens(node.body) && precedence(node.body) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
                         report(node.body);
                     }
                 }
@@ -535,27 +500,8 @@ module.exports = {
                 }
             },
 
-            ExpressionStatement(node) {
-                if (hasExcessParens(node.expression)) {
-                    const firstTokens = sourceCode.getFirstTokens(node.expression, 2);
-                    const firstToken = firstTokens[0];
-                    const secondToken = firstTokens[1];
-
-                    if (
-                        !firstToken ||
-                        firstToken.value !== "{" &&
-                        firstToken.value !== "function" &&
-                        firstToken.value !== "class" &&
-                        (
-                            firstToken.value !== "let" ||
-                            !secondToken ||
-                            secondToken.value !== "["
-                        )
-                    ) {
-                        report(node.expression);
-                    }
-                }
-            },
+            ExportDefaultDeclaration: node => checkExpressionOrExportStatement(node.declaration),
+            ExpressionStatement: node => checkExpressionOrExportStatement(node.expression),
 
             ForInStatement(node) {
                 if (hasExcessParens(node.right)) {
@@ -598,18 +544,11 @@ module.exports = {
                     (
                         node.computed ||
                         !(
-                            (node.object.type === "Literal" &&
-                            typeof node.object.value === "number" &&
-                            astUtils.isDecimalInteger(node.object)) ||
+                            astUtils.isDecimalInteger(node.object) ||
 
                             // RegExp literal is allowed to have parens (#1589)
                             (node.object.type === "Literal" && node.object.regex)
                         )
-                    ) &&
-                    !(
-                        (node.object.type === "FunctionExpression" || node.object.type === "ClassExpression") &&
-                        isHeadOfExpressionStatement(node) &&
-                        !hasDoubleExcessParens(node.object)
                     )
                 ) {
                     report(node.object);
diff --git a/lib/rules/no-loop-func.js b/lib/rules/no-loop-func.js
index b8bed9586..df0f17678 100644
--- a/lib/rules/no-loop-func.js
+++ b/lib/rules/no-loop-func.js
@@ -90,7 +90,7 @@ function getTopLoopNode(node, excludedNode) {
  *
  * @param {ASTNode} funcNode - A target function node.
  * @param {ASTNode} loopNode - A containing loop node.
- * @param {escope.Reference} reference - A reference to check.
+ * @param {eslint-scope.Reference} reference - A reference to check.
  * @returns {boolean} `true` if the reference is safe or not.
  */
 function isSafe(funcNode, loopNode, reference) {
@@ -131,7 +131,7 @@ function isSafe(funcNode, loopNode, reference) {
      * - is readonly.
      * - doesn't exist inside a local function and after the border.
      *
-     * @param {escope.Reference} upperRef - A reference to check.
+     * @param {eslint-scope.Reference} upperRef - A reference to check.
      * @returns {boolean} `true` if the reference is safe.
      */
     function isSafeReference(upperRef) {
diff --git a/lib/rules/no-native-reassign.js b/lib/rules/no-native-reassign.js
index f721fc278..d3dfefbaf 100644
--- a/lib/rules/no-native-reassign.js
+++ b/lib/rules/no-native-reassign.js
@@ -15,7 +15,7 @@ module.exports = {
         docs: {
             description: "disallow assignments to native objects or read-only global variables",
             category: "Best Practices",
-            recommended: true,
+            recommended: false,
             replacedBy: ["no-global-assign"]
         },
 
diff --git a/lib/rules/no-negated-in-lhs.js b/lib/rules/no-negated-in-lhs.js
index 143518060..495cbc160 100644
--- a/lib/rules/no-negated-in-lhs.js
+++ b/lib/rules/no-negated-in-lhs.js
@@ -15,7 +15,7 @@ module.exports = {
         docs: {
             description: "disallow negating the left operand in `in` expressions",
             category: "Possible Errors",
-            recommended: true,
+            recommended: false,
             replacedBy: ["no-unsafe-negation"]
         },
         deprecated: true,
diff --git a/lib/rules/no-redeclare.js b/lib/rules/no-redeclare.js
index bfbc09ffb..ccb57003e 100644
--- a/lib/rules/no-redeclare.js
+++ b/lib/rules/no-redeclare.js
@@ -35,7 +35,7 @@ module.exports = {
 
         /**
          * Find variables in a given scope and flag redeclared ones.
-         * @param {Scope} scope - An escope scope object.
+         * @param {Scope} scope - An eslint-scope scope object.
          * @returns {void}
          * @private
          */
diff --git a/lib/rules/no-restricted-syntax.js b/lib/rules/no-restricted-syntax.js
index d87e589c7..1798065ec 100644
--- a/lib/rules/no-restricted-syntax.js
+++ b/lib/rules/no-restricted-syntax.js
@@ -18,18 +18,45 @@ module.exports = {
 
         schema: {
             type: "array",
-            items: [{ type: "string" }],
+            items: [{
+                oneOf: [
+                    {
+                        type: "string"
+                    },
+                    {
+                        type: "object",
+                        properties: {
+                            selector: { type: "string" },
+                            message: { type: "string" }
+                        },
+                        required: ["selector"],
+                        additionalProperties: false
+                    }
+                ]
+            }],
             uniqueItems: true,
             minItems: 0
         }
     },
 
     create(context) {
-        return context.options.reduce((result, selector) => Object.assign(result, {
-            [selector](node) {
-                context.report({ node, message: "Using '{{selector}}' is not allowed.", data: { selector } });
-            }
-        }), {});
+        return context.options.reduce((result, selectorOrObject) => {
+            const isStringFormat = (typeof selectorOrObject === "string");
+            const hasCustomMessage = !isStringFormat && Boolean(selectorOrObject.message);
+
+            const selector = isStringFormat ? selectorOrObject : selectorOrObject.selector;
+            const message = hasCustomMessage ? selectorOrObject.message : "Using '{{selector}}' is not allowed.";
+
+            return Object.assign(result, {
+                [selector](node) {
+                    context.report({
+                        node,
+                        message,
+                        data: hasCustomMessage ? {} : { selector }
+                    });
+                }
+            });
+        }, {});
 
     }
 };
diff --git a/lib/rules/no-undefined.js b/lib/rules/no-undefined.js
index d29ac1e72..7e9f96b92 100644
--- a/lib/rules/no-undefined.js
+++ b/lib/rules/no-undefined.js
@@ -36,7 +36,7 @@ module.exports = {
         /**
          * Checks the given scope for references to `undefined` and reports
          * all references found.
-         * @param {escope.Scope} scope The scope to check.
+         * @param {eslint-scope.Scope} scope The scope to check.
          * @returns {void}
          */
         function checkScope(scope) {
diff --git a/lib/rules/no-unmodified-loop-condition.js b/lib/rules/no-unmodified-loop-condition.js
index 824361191..41d93d8af 100644
--- a/lib/rules/no-unmodified-loop-condition.js
+++ b/lib/rules/no-unmodified-loop-condition.js
@@ -25,7 +25,7 @@ const DYNAMIC_PATTERN = /^(?:Call|Member|New|TaggedTemplate|Yield)Expression$/;
 
 /**
  * @typedef {Object} LoopConditionInfo
- * @property {escope.Reference} reference - The reference.
+ * @property {eslint-scope.Reference} reference - The reference.
  * @property {ASTNode} group - BinaryExpression or ConditionalExpression nodes
  *      that the reference is belonging to.
  * @property {Function} isInLoop - The predicate which checks a given reference
@@ -37,7 +37,7 @@ const DYNAMIC_PATTERN = /^(?:Call|Member|New|TaggedTemplate|Yield)Expression$/;
 /**
  * Checks whether or not a given reference is a write reference.
  *
- * @param {escope.Reference} reference - A reference to check.
+ * @param {eslint-scope.Reference} reference - A reference to check.
  * @returns {boolean} `true` if the reference is a write reference.
  */
 function isWriteReference(reference) {
@@ -77,7 +77,7 @@ function isUnmodifiedAndNotBelongToGroup(condition) {
  * Checks whether or not a given reference is inside of a given node.
  *
  * @param {ASTNode} node - A node to check.
- * @param {escope.Reference} reference - A reference to check.
+ * @param {eslint-scope.Reference} reference - A reference to check.
  * @returns {boolean} `true` if the reference is inside of the node.
  */
 function isInRange(node, reference) {
@@ -91,7 +91,7 @@ function isInRange(node, reference) {
  * Checks whether or not a given reference is inside of a loop node's condition.
  *
  * @param {ASTNode} node - A node to check.
- * @param {escope.Reference} reference - A reference to check.
+ * @param {eslint-scope.Reference} reference - A reference to check.
  * @returns {boolean} `true` if the reference is inside of the loop node's
  *      condition.
  */
@@ -134,7 +134,7 @@ function hasDynamicExpressions(root) {
 /**
  * Creates the loop condition information from a given reference.
  *
- * @param {escope.Reference} reference - A reference to create.
+ * @param {eslint-scope.Reference} reference - A reference to create.
  * @returns {LoopConditionInfo|null} Created loop condition info, or null.
  */
 function toLoopCondition(reference) {
@@ -188,7 +188,7 @@ function toLoopCondition(reference) {
  * Gets the function which encloses a given reference.
  * This supports only FunctionDeclaration.
  *
- * @param {escope.Reference} reference - A reference to get.
+ * @param {eslint-scope.Reference} reference - A reference to get.
  * @returns {ASTNode|null} The function node or null.
  */
 function getEncloseFunctionDeclaration(reference) {
@@ -209,7 +209,7 @@ function getEncloseFunctionDeclaration(reference) {
  * Updates the "modified" flags of given loop conditions with given modifiers.
  *
  * @param {LoopConditionInfo[]} conditions - The loop conditions to be updated.
- * @param {escope.Reference[]} modifiers - The references to update.
+ * @param {eslint-scope.Reference[]} modifiers - The references to update.
  * @returns {void}
  */
 function updateModifiedFlag(conditions, modifiers) {
@@ -311,7 +311,7 @@ module.exports = {
          * Finds unmodified references which are inside of a loop condition.
          * Then reports the references which are outside of groups.
          *
-         * @param {escope.Variable} variable - A variable to report.
+         * @param {eslint-scope.Variable} variable - A variable to report.
          * @returns {void}
          */
         function checkReferences(variable) {
diff --git a/lib/rules/no-unsafe-negation.js b/lib/rules/no-unsafe-negation.js
index 4e2378d4d..761dc0338 100644
--- a/lib/rules/no-unsafe-negation.js
+++ b/lib/rules/no-unsafe-negation.js
@@ -44,7 +44,7 @@ module.exports = {
         docs: {
             description: "disallow negating the left operand of relational operators",
             category: "Possible Errors",
-            recommended: false
+            recommended: true
         },
         schema: [],
         fixable: "code"
diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
index 6f2703967..3ff9bc64f 100644
--- a/lib/rules/no-unused-vars.js
+++ b/lib/rules/no-unused-vars.js
@@ -108,7 +108,7 @@ module.exports = {
 
         /**
          * Determines if a given variable is being exported from a module.
-         * @param {Variable} variable - EScope variable object.
+         * @param {Variable} variable - eslint-scope variable object.
          * @returns {boolean} True if the variable is exported, false if not.
          * @private
          */
@@ -134,7 +134,7 @@ module.exports = {
 
         /**
          * Determines if a variable has a sibling rest property
-         * @param {Variable} variable - EScope variable object.
+         * @param {Variable} variable - eslint-scope variable object.
          * @returns {boolean} True if the variable is exported, false if not.
          * @private
          */
@@ -157,7 +157,7 @@ module.exports = {
 
         /**
          * Determines if a reference is a read operation.
-         * @param {Reference} ref - An escope Reference
+         * @param {Reference} ref - An eslint-scope Reference
          * @returns {boolean} whether the given reference represents a read operation
          * @private
          */
@@ -212,7 +212,7 @@ module.exports = {
          * - The reference is inside of a function scope which is different from
          *   the declaration.
          *
-         * @param {escope.Reference} ref - A reference to check.
+         * @param {eslint-scope.Reference} ref - A reference to check.
          * @param {ASTNode} prevRhsNode - The previous RHS node.
          * @returns {ASTNode|null} The RHS node or null.
          * @private
@@ -322,7 +322,7 @@ module.exports = {
         /**
          * Checks whether a given reference is a read to update itself or not.
          *
-         * @param {escope.Reference} ref - A reference to check.
+         * @param {eslint-scope.Reference} ref - A reference to check.
          * @param {ASTNode} rhsNode - The RHS node of the previous assignment.
          * @returns {boolean} The reference is a read to update itself.
          * @private
@@ -422,7 +422,7 @@ module.exports = {
         /**
          * Checks whether the given variable is the last parameter in the non-ignored parameters.
          *
-         * @param {escope.Variable} variable - The variable to check.
+         * @param {eslint-scope.Variable} variable - The variable to check.
          * @returns {boolean} `true` if the variable is the last.
          */
         function isLastInNonIgnoredParameters(variable) {
@@ -448,7 +448,7 @@ module.exports = {
 
         /**
          * Gets an array of variables without read references.
-         * @param {Scope} scope - an escope Scope object.
+         * @param {Scope} scope - an eslint-scope Scope object.
          * @param {Variable[]} unusedVars - an array that saving result.
          * @returns {Variable[]} unused variables of the scope and descendant scopes.
          * @private
@@ -540,7 +540,7 @@ module.exports = {
 
         /**
          * Gets the index of a given variable name in a given comment.
-         * @param {escope.Variable} variable - A variable to get.
+         * @param {eslint-scope.Variable} variable - A variable to get.
          * @param {ASTNode} comment - A comment node which includes the variable name.
          * @returns {number} The index of the variable name's location.
          * @private
@@ -561,7 +561,7 @@ module.exports = {
          * Creates the correct location of a given variables.
          * The location is at its name string in a `/*global` comment.
          *
-         * @param {escope.Variable} variable - A variable to get its location.
+         * @param {eslint-scope.Variable} variable - A variable to get its location.
          * @returns {{line: number, column: number}} The location object for the variable.
          * @private
          */
diff --git a/lib/rules/no-use-before-define.js b/lib/rules/no-use-before-define.js
index 1a779b86f..6d01e3e10 100644
--- a/lib/rules/no-use-before-define.js
+++ b/lib/rules/no-use-before-define.js
@@ -37,7 +37,7 @@ function parseOptions(options) {
 /**
  * Checks whether or not a given variable is a function declaration.
  *
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is a function declaration.
  */
 function isFunction(variable) {
@@ -47,8 +47,8 @@ function isFunction(variable) {
 /**
  * Checks whether or not a given variable is a class declaration in an upper function scope.
  *
- * @param {escope.Variable} variable - A variable to check.
- * @param {escope.Reference} reference - A reference to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Reference} reference - A reference to check.
  * @returns {boolean} `true` if the variable is a class declaration.
  */
 function isOuterClass(variable, reference) {
@@ -60,8 +60,8 @@ function isOuterClass(variable, reference) {
 
 /**
 * Checks whether or not a given variable is a variable declaration in an upper function scope.
-* @param {escope.Variable} variable - A variable to check.
-* @param {escope.Reference} reference - A reference to check.
+* @param {eslint-scope.Variable} variable - A variable to check.
+* @param {eslint-scope.Reference} reference - A reference to check.
 * @returns {boolean} `true` if the variable is a variable declaration.
 */
 function isOuterVariable(variable, reference) {
@@ -167,8 +167,8 @@ module.exports = {
 
         /**
          * Determines whether a given use-before-define case should be reported according to the options.
-         * @param {escope.Variable} variable The variable that gets used before being defined
-         * @param {escope.Reference} reference The reference to the variable
+         * @param {eslint-scope.Variable} variable The variable that gets used before being defined
+         * @param {eslint-scope.Reference} reference The reference to the variable
          * @returns {boolean} `true` if the usage should be reported
          */
         function isForbidden(variable, reference) {
diff --git a/lib/rules/no-var.js b/lib/rules/no-var.js
index 86373ad50..c74e0b9ad 100644
--- a/lib/rules/no-var.js
+++ b/lib/rules/no-var.js
@@ -19,8 +19,8 @@ const astUtils = require("../ast-utils");
  * Finds the nearest function scope or global scope walking up the scope
  * hierarchy.
  *
- * @param {escope.Scope} scope - The scope to traverse.
- * @returns {escope.Scope} a function scope or global scope containing the given
+ * @param {eslint-scope.Scope} scope - The scope to traverse.
+ * @returns {eslint-scope.Scope} a function scope or global scope containing the given
  *      scope.
  */
 function getEnclosingFunctionScope(scope) {
@@ -34,7 +34,7 @@ function getEnclosingFunctionScope(scope) {
  * Checks whether the given variable has any references from a more specific
  * function expression (i.e. a closure).
  *
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is used from a closure.
  */
 function isReferencedInClosure(variable) {
@@ -93,7 +93,7 @@ function getScopeNode(node) {
 /**
  * Checks whether a given variable is redeclared or not.
  *
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is redeclared.
  */
 function isRedeclared(variable) {
@@ -112,7 +112,7 @@ function isUsedFromOutsideOf(scopeNode) {
     /**
      * Checks whether a given reference is inside of the specified scope or not.
      *
-     * @param {escope.Reference} reference - A reference to check.
+     * @param {eslint-scope.Reference} reference - A reference to check.
      * @returns {boolean} `true` if the reference is inside of the specified
      *      scope.
      */
diff --git a/lib/rules/operator-assignment.js b/lib/rules/operator-assignment.js
index 1c40eed15..99cca356f 100644
--- a/lib/rules/operator-assignment.js
+++ b/lib/rules/operator-assignment.js
@@ -4,6 +4,12 @@
  */
 "use strict";
 
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const astUtils = require("../ast-utils");
+
 //------------------------------------------------------------------------------
 // Helpers
 //------------------------------------------------------------------------------
@@ -171,9 +177,20 @@ module.exports = {
                         if (canBeFixed(node.left)) {
                             const operatorToken = getOperatorToken(node);
                             const leftText = sourceCode.getText().slice(node.range[0], operatorToken.range[0]);
-                            const rightText = sourceCode.getText().slice(operatorToken.range[1], node.range[1]);
+                            const newOperator = node.operator.slice(0, -1);
+                            let rightText;
+
+                            // If this change would modify precedence (e.g. `foo *= bar + 1` => `foo = foo * (bar + 1)`), parenthesize the right side.
+                            if (
+                                astUtils.getPrecedence(node.right) <= astUtils.getPrecedence({ type: "BinaryExpression", operator: newOperator }) &&
+                                !astUtils.isParenthesised(sourceCode, node.right)
+                            ) {
+                                rightText = `${sourceCode.text.slice(operatorToken.range[1], node.right.range[0])}(${sourceCode.getText(node.right)})`;
+                            } else {
+                                rightText = sourceCode.text.slice(operatorToken.range[1], node.range[1]);
+                            }
 
-                            return fixer.replaceText(node, `${leftText}= ${leftText}${node.operator.slice(0, -1)}${rightText}`);
+                            return fixer.replaceText(node, `${leftText}= ${leftText}${newOperator}${rightText}`);
                         }
                         return null;
                     }
diff --git a/lib/rules/padded-blocks.js b/lib/rules/padded-blocks.js
index 36036aec4..a485c1770 100644
--- a/lib/rules/padded-blocks.js
+++ b/lib/rules/padded-blocks.js
@@ -51,7 +51,11 @@ module.exports = {
         const config = context.options[0] || "always";
 
         if (typeof config === "string") {
-            options.blocks = config === "always";
+            const shouldHavePadding = config === "always";
+
+            options.blocks = shouldHavePadding;
+            options.switches = shouldHavePadding;
+            options.classes = shouldHavePadding;
         } else {
             if (config.hasOwnProperty("blocks")) {
                 options.blocks = config.blocks === "always";
diff --git a/lib/rules/prefer-arrow-callback.js b/lib/rules/prefer-arrow-callback.js
index ee385042f..b9cde17ca 100644
--- a/lib/rules/prefer-arrow-callback.js
+++ b/lib/rules/prefer-arrow-callback.js
@@ -11,7 +11,7 @@
 
 /**
  * Checks whether or not a given variable is a function name.
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is a function name.
  */
 function isFunctionName(variable) {
@@ -31,8 +31,8 @@ function checkMetaProperty(node, metaName, propertyName) {
 
 /**
  * Gets the variable object of `arguments` which is defined implicitly.
- * @param {escope.Scope} scope - A scope to get.
- * @returns {escope.Variable} The found variable object.
+ * @param {eslint-scope.Scope} scope - A scope to get.
+ * @returns {eslint-scope.Variable} The found variable object.
  */
 function getVariableOfArguments(scope) {
     const variables = scope.variables;
diff --git a/lib/rules/prefer-const.js b/lib/rules/prefer-const.js
index 53bdc2ab7..595bb8a53 100644
--- a/lib/rules/prefer-const.js
+++ b/lib/rules/prefer-const.js
@@ -73,7 +73,7 @@ function canBecomeVariableDeclaration(identifier) {
  *   warn such variables because this rule cannot distinguish whether the
  *   exported variables are reassigned or not.
  *
- * @param {escope.Variable} variable - A variable to get.
+ * @param {eslint-scope.Variable} variable - A variable to get.
  * @param {boolean} ignoreReadBeforeAssign -
  *      The value of `ignoreReadBeforeAssign` option.
  * @returns {ASTNode|null}
@@ -146,7 +146,7 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
  * This is used to detect a mix of reassigned and never reassigned in a
  * destructuring.
  *
- * @param {escope.Reference} reference - A reference to get.
+ * @param {eslint-scope.Reference} reference - A reference to get.
  * @returns {ASTNode|null} A VariableDeclarator/AssignmentExpression node or
  *      null.
  */
@@ -172,7 +172,7 @@ function getDestructuringHost(reference) {
  * This is used to detect a mix of reassigned and never reassigned in a
  * destructuring.
  *
- * @param {escope.Variable[]} variables - Variables to group by destructuring.
+ * @param {eslint-scope.Variable[]} variables - Variables to group by destructuring.
  * @param {boolean} ignoreReadBeforeAssign -
  *      The value of `ignoreReadBeforeAssign` option.
  * @returns {Map<ASTNode, ASTNode[]>} Grouped identifier nodes.
@@ -274,7 +274,7 @@ module.exports = {
          * the array is 1. In destructuring cases, the length of the array can
          * be 2 or more.
          *
-         * @param {(escope.Reference|null)[]} nodes -
+         * @param {(eslint-scope.Reference|null)[]} nodes -
          *      References which are grouped by destructuring to report.
          * @returns {void}
          */
diff --git a/lib/rules/prefer-rest-params.js b/lib/rules/prefer-rest-params.js
index a9db624dc..d55d5dad0 100644
--- a/lib/rules/prefer-rest-params.js
+++ b/lib/rules/prefer-rest-params.js
@@ -11,8 +11,8 @@
 
 /**
  * Gets the variable object of `arguments` which is defined implicitly.
- * @param {escope.Scope} scope - A scope to get.
- * @returns {escope.Variable} The found variable object.
+ * @param {eslint-scope.Scope} scope - A scope to get.
+ * @returns {eslint-scope.Variable} The found variable object.
  */
 function getVariableOfArguments(scope) {
     const variables = scope.variables;
@@ -40,7 +40,7 @@ function getVariableOfArguments(scope) {
  * - arguments[0]      .... true    // computed member access
  * - arguments.length  .... false   // normal member access
  *
- * @param {escope.Reference} reference - The reference to check.
+ * @param {eslint-scope.Reference} reference - The reference to check.
  * @returns {boolean} `true` if the reference is not normal member access.
  */
 function isNotNormalMemberAccess(reference) {
@@ -74,7 +74,7 @@ module.exports = {
         /**
          * Reports a given reference.
          *
-         * @param {escope.Reference} reference - A reference to report.
+         * @param {eslint-scope.Reference} reference - A reference to report.
          * @returns {void}
          */
         function report(reference) {
diff --git a/lib/rules/radix.js b/lib/rules/radix.js
index 0dfa081b6..0484c3bfb 100644
--- a/lib/rules/radix.js
+++ b/lib/rules/radix.js
@@ -21,7 +21,7 @@ const MODE_ALWAYS = "always",
 /**
  * Checks whether a given variable is shadowed or not.
  *
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is shadowed.
  */
 function isShadowed(variable) {
diff --git a/lib/rules/space-before-function-paren.js b/lib/rules/space-before-function-paren.js
index c36c5a953..53aac71ed 100644
--- a/lib/rules/space-before-function-paren.js
+++ b/lib/rules/space-before-function-paren.js
@@ -102,34 +102,43 @@ module.exports = {
             return "ignore";
         }
 
-        return {
-            ":function"(node) {
-                const functionConfig = getConfigForFunction(node);
+        /**
+         * Checks the parens of a function node
+         * @param {ASTNode} node A function node
+         * @returns {void}
+         */
+        function checkFunction(node) {
+            const functionConfig = getConfigForFunction(node);
 
-                if (functionConfig === "ignore") {
-                    return;
-                }
+            if (functionConfig === "ignore") {
+                return;
+            }
 
-                const rightToken = sourceCode.getFirstToken(node, astUtils.isOpeningParenToken);
-                const leftToken = sourceCode.getTokenBefore(rightToken);
-                const hasSpacing = sourceCode.isSpaceBetweenTokens(leftToken, rightToken);
-
-                if (hasSpacing && functionConfig === "never") {
-                    context.report({
-                        node,
-                        loc: leftToken.loc.end,
-                        message: "Unexpected space before function parentheses.",
-                        fix: fixer => fixer.removeRange([leftToken.range[1], rightToken.range[0]])
-                    });
-                } else if (!hasSpacing && functionConfig === "always") {
-                    context.report({
-                        node,
-                        loc: leftToken.loc.end,
-                        message: "Missing space before function parentheses.",
-                        fix: fixer => fixer.insertTextAfter(leftToken, " ")
-                    });
-                }
+            const rightToken = sourceCode.getFirstToken(node, astUtils.isOpeningParenToken);
+            const leftToken = sourceCode.getTokenBefore(rightToken);
+            const hasSpacing = sourceCode.isSpaceBetweenTokens(leftToken, rightToken);
+
+            if (hasSpacing && functionConfig === "never") {
+                context.report({
+                    node,
+                    loc: leftToken.loc.end,
+                    message: "Unexpected space before function parentheses.",
+                    fix: fixer => fixer.removeRange([leftToken.range[1], rightToken.range[0]])
+                });
+            } else if (!hasSpacing && functionConfig === "always") {
+                context.report({
+                    node,
+                    loc: leftToken.loc.end,
+                    message: "Missing space before function parentheses.",
+                    fix: fixer => fixer.insertTextAfter(leftToken, " ")
+                });
             }
+        }
+
+        return {
+            ArrowFunctionExpression: checkFunction,
+            FunctionDeclaration: checkFunction,
+            FunctionExpression: checkFunction
         };
     }
 };
diff --git a/lib/util/glob-util.js b/lib/util/glob-util.js
index d414f783f..4c21fc551 100644
--- a/lib/util/glob-util.js
+++ b/lib/util/glob-util.js
@@ -86,7 +86,7 @@ function resolveFileGlobPatterns(patterns, options) {
 
     const processPathExtensions = processPath(options);
 
-    return patterns.map(processPathExtensions);
+    return patterns.filter(p => p.length).map(processPathExtensions);
 }
 
 /**
diff --git a/package.json b/package.json
index 0a7ac385d..eafb1cdd3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint",
-  "version": "3.18.0",
+  "version": "3.19.0",
   "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
   "description": "An AST-based pattern checker for JavaScript.",
   "bin": {
@@ -39,7 +39,7 @@
     "concat-stream": "^1.5.2",
     "debug": "^2.1.1",
     "doctrine": "^2.0.0",
-    "escope": "^3.6.0",
+    "eslint-scope": "^3.6.0",
     "espree": "^3.4.0",
     "esquery": "^1.0.0",
     "estraverse": "^4.2.0",


Test patch:
diff --git a/tests/fixtures/parsers/babel-eslint7/function-type-annotation.js b/tests/fixtures/parsers/babel-eslint7/function-type-annotation.js
new file mode 100644
index 000000000..a663b4e1e
--- /dev/null
+++ b/tests/fixtures/parsers/babel-eslint7/function-type-annotation.js
@@ -0,0 +1,525 @@
+"use strict";
+
+/**
+ * Parser: babel-eslint v7.2.1
+ * Source code:
+ * type TransformFunction = (el: ASTElement, code: string) => string;
+ */
+
+exports.parse = () => ({
+    type: "Program",
+    start: 0,
+    end: 66,
+    loc: {
+        start: {
+            line: 1,
+            column: 0
+        },
+        end: {
+            line: 1,
+            column: 66
+        }
+    },
+    comments: [],
+    tokens: [
+        {
+            type: "Identifier",
+            value: "type",
+            start: 0,
+            end: 4,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 0
+                },
+                end: {
+                    line: 1,
+                    column: 4
+                }
+            },
+            range: [
+                0,
+                4
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "TransformFunction",
+            start: 5,
+            end: 22,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 5
+                },
+                end: {
+                    line: 1,
+                    column: 22
+                }
+            },
+            range: [
+                5,
+                22
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: "=",
+            start: 23,
+            end: 24,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 23
+                },
+                end: {
+                    line: 1,
+                    column: 24
+                }
+            },
+            range: [
+                23,
+                24
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: "(",
+            start: 25,
+            end: 26,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 25
+                },
+                end: {
+                    line: 1,
+                    column: 26
+                }
+            },
+            range: [
+                25,
+                26
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "el",
+            start: 26,
+            end: 28,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 26
+                },
+                end: {
+                    line: 1,
+                    column: 28
+                }
+            },
+            range: [
+                26,
+                28
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: ":",
+            start: 28,
+            end: 29,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 28
+                },
+                end: {
+                    line: 1,
+                    column: 29
+                }
+            },
+            range: [
+                28,
+                29
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "ASTElement",
+            start: 30,
+            end: 40,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 30
+                },
+                end: {
+                    line: 1,
+                    column: 40
+                }
+            },
+            range: [
+                30,
+                40
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: ",",
+            start: 40,
+            end: 41,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 40
+                },
+                end: {
+                    line: 1,
+                    column: 41
+                }
+            },
+            range: [
+                40,
+                41
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "code",
+            start: 42,
+            end: 46,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 42
+                },
+                end: {
+                    line: 1,
+                    column: 46
+                }
+            },
+            range: [
+                42,
+                46
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: ":",
+            start: 46,
+            end: 47,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 46
+                },
+                end: {
+                    line: 1,
+                    column: 47
+                }
+            },
+            range: [
+                46,
+                47
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "string",
+            start: 48,
+            end: 54,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 48
+                },
+                end: {
+                    line: 1,
+                    column: 54
+                }
+            },
+            range: [
+                48,
+                54
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: ")",
+            start: 54,
+            end: 55,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 54
+                },
+                end: {
+                    line: 1,
+                    column: 55
+                }
+            },
+            range: [
+                54,
+                55
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: "=>",
+            start: 56,
+            end: 58,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 56
+                },
+                end: {
+                    line: 1,
+                    column: 58
+                }
+            },
+            range: [
+                56,
+                58
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "string",
+            start: 59,
+            end: 65,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 59
+                },
+                end: {
+                    line: 1,
+                    column: 65
+                }
+            },
+            range: [
+                59,
+                65
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: ";",
+            start: 65,
+            end: 66,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 65
+                },
+                end: {
+                    line: 1,
+                    column: 66
+                }
+            },
+            range: [
+                65,
+                66
+            ]
+        }
+    ],
+    range: [
+        0,
+        66
+    ],
+    sourceType: "module",
+    body: [
+        {
+            type: "TypeAlias",
+            start: 0,
+            end: 66,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 0
+                },
+                end: {
+                    line: 1,
+                    column: 66
+                }
+            },
+            id: {
+                type: "Identifier",
+                start: 5,
+                end: 22,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 5
+                    },
+                    end: {
+                        line: 1,
+                        column: 22
+                    },
+                    identifierName: "TransformFunction"
+                },
+                name: "TransformFunction",
+                range: [
+                    5,
+                    22
+                ],
+                _babelType: "Identifier"
+            },
+            typeParameters: null,
+            right: {
+                type: "FunctionTypeAnnotation",
+                start: 25,
+                end: 65,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 25
+                    },
+                    end: {
+                        line: 1,
+                        column: 65
+                    }
+                },
+                params: [
+                    {
+                        type: "FunctionTypeParam",
+                        start: 26,
+                        end: 40,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 26
+                            },
+                            end: {
+                                line: 1,
+                                column: 40
+                            }
+                        },
+                        optional: false,
+                        typeAnnotation: {
+                            type: "GenericTypeAnnotation",
+                            start: 30,
+                            end: 40,
+                            loc: {
+                                start: {
+                                    line: 1,
+                                    column: 30
+                                },
+                                end: {
+                                    line: 1,
+                                    column: 40
+                                }
+                            },
+                            typeParameters: null,
+                            id: {
+                                type: "Identifier",
+                                start: 30,
+                                end: 40,
+                                loc: {
+                                    start: {
+                                        line: 1,
+                                        column: 30
+                                    },
+                                    end: {
+                                        line: 1,
+                                        column: 40
+                                    },
+                                    identifierName: "ASTElement"
+                                },
+                                name: "ASTElement",
+                                range: [
+                                    30,
+                                    40
+                                ],
+                                _babelType: "Identifier"
+                            },
+                            range: [
+                                30,
+                                40
+                            ],
+                            _babelType: "GenericTypeAnnotation"
+                        },
+                        range: [
+                            26,
+                            40
+                        ],
+                        _babelType: "FunctionTypeParam"
+                    },
+                    {
+                        type: "FunctionTypeParam",
+                        start: 42,
+                        end: 54,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 42
+                            },
+                            end: {
+                                line: 1,
+                                column: 54
+                            }
+                        },
+                        optional: false,
+                        typeAnnotation: {
+                            type: "StringTypeAnnotation",
+                            start: 48,
+                            end: 54,
+                            loc: {
+                                start: {
+                                    line: 1,
+                                    column: 48
+                                },
+                                end: {
+                                    line: 1,
+                                    column: 54
+                                }
+                            },
+                            range: [
+                                48,
+                                54
+                            ],
+                            _babelType: "StringTypeAnnotation"
+                        },
+                        range: [
+                            42,
+                            54
+                        ],
+                        _babelType: "FunctionTypeParam"
+                    }
+                ],
+                rest: null,
+                returnType: {
+                    type: "StringTypeAnnotation",
+                    start: 59,
+                    end: 65,
+                    loc: {
+                        start: {
+                            line: 1,
+                            column: 59
+                        },
+                        end: {
+                            line: 1,
+                            column: 65
+                        }
+                    },
+                    range: [
+                        59,
+                        65
+                    ],
+                    _babelType: "StringTypeAnnotation"
+                },
+                typeParameters: null,
+                range: [
+                    25,
+                    65
+                ],
+                _babelType: "FunctionTypeAnnotation"
+            },
+            range: [
+                0,
+                66
+            ],
+            _babelType: "TypeAlias"
+        }
+    ]
+});
diff --git a/tests/lib/ast-utils.js b/tests/lib/ast-utils.js
index 448f9cde7..626497e77 100644
--- a/tests/lib/ast-utils.js
+++ b/tests/lib/ast-utils.js
@@ -214,7 +214,7 @@ describe("ast-utils", () => {
 
             eslint.reset();
             eslint.on("VariableDeclaration", checker);
-            eslint.verify("const a = 1; a = 2;", { ecmaFeatures: { blockBindings: true } }, filename, true);
+            eslint.verify("const a = 1; a = 2;", {}, filename, true);
         });
 
         it("should return false if reference is not assigned for const", () => {
@@ -232,7 +232,7 @@ describe("ast-utils", () => {
 
             eslint.reset();
             eslint.on("VariableDeclaration", checker);
-            eslint.verify("const a = 1; c = 2;", { ecmaFeatures: { blockBindings: true } }, filename, true);
+            eslint.verify("const a = 1; c = 2;", {}, filename, true);
         });
 
         // class
@@ -252,7 +252,7 @@ describe("ast-utils", () => {
 
             eslint.reset();
             eslint.on("ClassDeclaration", checker);
-            eslint.verify("class A { }\n A = 1;", { ecmaFeatures: { classes: true } }, filename, true);
+            eslint.verify("class A { }\n A = 1;", {}, filename, true);
         });
 
         it("should return false if reference is not assigned for class", () => {
@@ -270,7 +270,7 @@ describe("ast-utils", () => {
 
             eslint.reset();
             eslint.on("ClassDeclaration", checker);
-            eslint.verify("class A { } foo(A);", { ecmaFeatures: { classes: true } }, filename, true);
+            eslint.verify("class A { } foo(A);", {}, filename, true);
         });
     });
 
diff --git a/tests/lib/config.js b/tests/lib/config.js
index fbf65d67f..3bc5dc3b3 100644
--- a/tests/lib/config.js
+++ b/tests/lib/config.js
@@ -358,9 +358,6 @@ describe("Config", () => {
                         browser: true,
                         node: false
                     },
-                    ecmaFeatures: {
-                        globalReturn: false
-                    },
                     globals: environments.browser.globals
                 },
                 actual = configHelper.getConfig(file);
diff --git a/tests/lib/config/plugins.js b/tests/lib/config/plugins.js
index 61b759797..3d7b98032 100644
--- a/tests/lib/config/plugins.js
+++ b/tests/lib/config/plugins.js
@@ -154,33 +154,33 @@ describe("Plugins", () => {
             assert.equal(Rules.get("@scope/example/foo"), scopedPlugin.rules.foo);
         });
 
-        describe("(NOTE: those behavior will be removed by 4.0.0)", () => {
-            it("should load a scoped plugin when referenced by short name, and should get the plugin even if '@scope/' is omitted", () => {
+        describe("when referencing a scope plugin and omitting @scope/", () => {
+            it("should load a scoped plugin when referenced by short name, but should not get the plugin if '@scope/' is omitted", () => {
                 StubbedPlugins.load("@scope/example");
-                assert.equal(StubbedPlugins.get("example"), scopedPlugin);
+                assert.equal(StubbedPlugins.get("example"), null);
             });
 
-            it("should load a scoped plugin when referenced by long name, and should get the plugin even if '@scope/' is omitted", () => {
+            it("should load a scoped plugin when referenced by long name, but should not get the plugin if '@scope/' is omitted", () => {
                 StubbedPlugins.load("@scope/eslint-plugin-example");
-                assert.equal(StubbedPlugins.get("example"), scopedPlugin);
+                assert.equal(StubbedPlugins.get("example"), null);
             });
 
-            it("should register environments when scoped plugin has environments, and should get the environment even if '@scope/' is omitted", () => {
+            it("should register environments when scoped plugin has environments, but should not get the environment if '@scope/' is omitted", () => {
                 scopedPlugin.environments = {
                     foo: {}
                 };
                 StubbedPlugins.load("@scope/eslint-plugin-example");
 
-                assert.equal(Environments.get("example/foo"), scopedPlugin.environments.foo);
+                assert.equal(Environments.get("example/foo"), null);
             });
 
-            it("should register rules when scoped plugin has rules, and should get the rule even if '@scope/' is omitted", () => {
+            it("should register rules when scoped plugin has rules, but should not get the rule if '@scope/' is omitted", () => {
                 scopedPlugin.rules = {
                     foo: {}
                 };
                 StubbedPlugins.load("@scope/eslint-plugin-example");
 
-                assert.equal(Rules.get("example/foo"), scopedPlugin.rules.foo);
+                assert.equal(Rules.get("example/foo"), null);
             });
         });
     });
diff --git a/tests/lib/eslint.js b/tests/lib/eslint.js
index 9a1456cb1..904cb5f32 100644
--- a/tests/lib/eslint.js
+++ b/tests/lib/eslint.js
@@ -48,7 +48,7 @@ const TEST_CODE = "var answer = 6 * 7;",
 //------------------------------------------------------------------------------
 
 /**
- * Get variables in the current escope
+ * Get variables in the current scope
  * @param {Object} scope current scope
  * @param {string} name name of the variable to look for
  * @returns {ASTNode} The variable object
diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js
index 967d2df05..f554d88b5 100644
--- a/tests/lib/rules/no-extra-parens.js
+++ b/tests/lib/rules/no-extra-parens.js
@@ -426,6 +426,27 @@ ruleTester.run("no-extra-parens", rule, {
         {
             code: "() => ({ foo: 1 }.foo().bar + baz)",
             parserOptions: { ecmaVersion: 2015 }
+        },
+        {
+            code: "export default (function(){}).foo",
+            parserOptions: { ecmaVersion: 2015, sourceType: "module" }
+        },
+        {
+            code: "export default (class{}).foo",
+            parserOptions: { ecmaVersion: 2015, sourceType: "module" }
+        },
+        "({}).hasOwnProperty.call(foo, bar)",
+        "({}) ? foo() : bar()",
+        "({}) + foo",
+        "(function(){}) + foo",
+        "(let[foo]) = 1", // setting the 'foo' property of the 'let' variable to 1
+        {
+            code: "((function(){}).foo.bar)();",
+            options: ["functions"]
+        },
+        {
+            code: "((function(){}).foo)();",
+            options: ["functions"]
         }
     ],
 
@@ -545,8 +566,6 @@ ruleTester.run("no-extra-parens", rule, {
         invalid("bar((function(){}).foo(), 0);", "bar(function(){}.foo(), 0);", "FunctionExpression"),
         invalid("bar[(function(){}).foo()];", "bar[function(){}.foo()];", "FunctionExpression"),
         invalid("var bar = (function(){}).foo();", "var bar = function(){}.foo();", "FunctionExpression"),
-        invalid("((function(){}).foo.bar)();", "(function(){}.foo.bar)();", "FunctionExpression", null, { options: ["functions"] }),
-        invalid("((function(){}).foo)();", "(function(){}.foo)();", "FunctionExpression", null, { options: ["functions"] }),
 
         invalid("((class{})).foo();", "(class{}).foo();", "ClassExpression", null, { parserOptions: { ecmaVersion: 6 } }),
         invalid("((class{}).foo());", "(class{}).foo();", "CallExpression", null, { parserOptions: { ecmaVersion: 6 } }),
@@ -976,17 +995,12 @@ ruleTester.run("no-extra-parens", rule, {
             1,
             { parserOptions: { ecmaVersion: 2015 } }
         ),
-        {
-            code: "() => (({ foo: 1 }).foo)",
-            output: "() => ({ foo: 1 }).foo",
-            parserOptions: { ecmaVersion: 2015 },
-            errors: [
-
-                // 2 errors are reported, but fixing one gets rid of the other
-                { message: "Gratuitous parentheses around expression.", type: "MemberExpression" },
-                { message: "Gratuitous parentheses around expression.", type: "ObjectExpression" }
-            ]
-
-        }
+        invalid(
+            "() => (({ foo: 1 }).foo)",
+            "() => ({ foo: 1 }).foo",
+            "MemberExpression",
+            1,
+            { parserOptions: { ecmaVersion: 2015 } }
+        )
     ]
 });
diff --git a/tests/lib/rules/no-restricted-syntax.js b/tests/lib/rules/no-restricted-syntax.js
index 7547e302b..3a653a978 100644
--- a/tests/lib/rules/no-restricted-syntax.js
+++ b/tests/lib/rules/no-restricted-syntax.js
@@ -19,6 +19,8 @@ const ruleTester = new RuleTester();
 
 ruleTester.run("no-restricted-syntax", rule, {
     valid: [
+
+        // string format
         { code: "doSomething();" },
         { code: "var foo = 42;", options: ["ConditionalExpression"] },
         { code: "foo += 42;", options: ["VariableDeclaration", "FunctionExpression"] },
@@ -26,9 +28,19 @@ ruleTester.run("no-restricted-syntax", rule, {
         { code: "() => 5", options: ["ArrowFunctionExpression > BlockStatement"], parserOptions: { ecmaVersion: 6 } },
         { code: "({ foo: 1, bar: 2 })", options: ["Property > Literal.key"] },
         { code: "A: for (;;) break;", options: ["BreakStatement[label]"] },
-        { code: "function foo(bar, baz) {}", options: ["FunctionDeclaration[params.length>2]"] }
+        { code: "function foo(bar, baz) {}", options: ["FunctionDeclaration[params.length>2]"] },
+
+        //  object format
+        { code: "var foo = 42;", options: [{ selector: "ConditionalExpression" }] },
+        { code: "({ foo: 1, bar: 2 })", options: [{ selector: "Property > Literal.key" }] },
+        {
+            code: "({ foo: 1, bar: 2 })",
+            options: [{ selector: "FunctionDeclaration[params.length>2]", message: "custom error message." }]
+        }
     ],
     invalid: [
+
+        // string format
         {
             code: "var foo = 41;",
             options: ["VariableDeclaration"],
@@ -82,6 +94,30 @@ ruleTester.run("no-restricted-syntax", rule, {
             code: "function foo(bar, baz, qux) {}",
             options: ["FunctionDeclaration[params.length>2]"],
             errors: [{ message: "Using 'FunctionDeclaration[params.length>2]' is not allowed.", type: "FunctionDeclaration" }]
+        },
+
+        // object format
+        {
+            code: "var foo = 41;",
+            options: [{ selector: "VariableDeclaration" }],
+            errors: [{ message: "Using 'VariableDeclaration' is not allowed.", type: "VariableDeclaration" }]
+        },
+        {
+            code: "function foo(bar, baz, qux) {}",
+            options: [{ selector: "FunctionDeclaration[params.length>2]" }],
+            errors: [{ message: "Using 'FunctionDeclaration[params.length>2]' is not allowed.", type: "FunctionDeclaration" }]
+        },
+        {
+            code: "function foo(bar, baz, qux) {}",
+            options: [{ selector: "FunctionDeclaration[params.length>2]", message: "custom error message." }],
+            errors: [{ message: "custom error message.", type: "FunctionDeclaration" }]
+        },
+
+        // with object format, the custom message may contain the string '{{selector}}'
+        {
+            code: "function foo(bar, baz, qux) {}",
+            options: [{ selector: "FunctionDeclaration[params.length>2]", message: "custom message with {{selector}}" }],
+            errors: [{ message: "custom message with {{selector}}", type: "FunctionDeclaration" }]
         }
     ]
 });
diff --git a/tests/lib/rules/operator-assignment.js b/tests/lib/rules/operator-assignment.js
index 5e5e65564..fb1ff889e 100644
--- a/tests/lib/rules/operator-assignment.js
+++ b/tests/lib/rules/operator-assignment.js
@@ -81,7 +81,8 @@ ruleTester.run("operator-assignment", rule, {
         "x = x === y",
         "x = x !== y",
         "x = x && y",
-        "x = x || y"
+        "x = x || y",
+        "x = x * y + z"
     ],
 
     invalid: [{
@@ -214,6 +215,31 @@ ruleTester.run("operator-assignment", rule, {
         output: "foo = foo ** bar",
         options: ["never"],
         errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo *= bar + 1",
+        output: "foo = foo * (bar + 1)",
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo -= bar - baz",
+        output: "foo = foo - (bar - baz)",
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo += bar + baz",
+        output: "foo = foo + (bar + baz)", // addition is not associative in JS, e.g. (1 + 2) + '3' !== 1 + (2 + '3')
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo += bar = 1",
+        output: "foo = foo + (bar = 1)",
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo *= (bar + 1)",
+        output: "foo = foo * (bar + 1)",
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
     }]
 
 });
diff --git a/tests/lib/rules/padded-blocks.js b/tests/lib/rules/padded-blocks.js
index c9208183b..a691e1108 100644
--- a/tests/lib/rules/padded-blocks.js
+++ b/tests/lib/rules/padded-blocks.js
@@ -39,23 +39,14 @@ ruleTester.run("padded-blocks", rule, {
         { code: "{\n\na();\n\n/* comment */ }", options: ["always"] },
         { code: "{\n\na();\n\n/* comment */ }", options: [{ blocks: "always" }] },
 
-        // Ignore switches by default
-        { code: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}", options: ["always"] },
-        { code: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}", options: ["never"] },
-
-        // Ignore block statements if not configured
-        { code: "{\na();\n}", options: [{ switches: "always" }] },
-        { code: "{\n\na();\n\n}", options: [{ switches: "never" }] },
-
         { code: "switch (a) {}", options: [{ switches: "always" }] },
+        { code: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}", options: ["always"] },
         { code: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}", options: [{ switches: "always" }] },
         { code: "switch (a) {\n\n//comment\ncase 0: foo();//comment\n\n}", options: [{ switches: "always" }] },
         { code: "switch (a) {//coment\n\ncase 0: foo();\ncase 1: bar();\n\n/* comment */}", options: [{ switches: "always" }] },
 
-        // Ignore classes by default
-        { code: "class A{\nfoo(){}\n}", parserOptions: { ecmaVersion: 6 } },
         { code: "class A{\n\nfoo(){}\n\n}", parserOptions: { ecmaVersion: 6 } },
-
+        { code: "class A{\n\nfoo(){}\n\n}", parserOptions: { ecmaVersion: 6 }, options: ["always"] },
         { code: "class A{}", parserOptions: { ecmaVersion: 6 }, options: [{ classes: "always" }] },
         { code: "class A{\n\n}", parserOptions: { ecmaVersion: 6 }, options: [{ classes: "always" }] },
         { code: "class A{\n\nfoo(){}\n\n}", parserOptions: { ecmaVersion: 6 }, options: [{ classes: "always" }] },
@@ -75,8 +66,27 @@ ruleTester.run("padded-blocks", rule, {
         { code: "{\n\n// comment\nif (\n// comment\n a) {}\n\n }", options: ["always"] },
         { code: "{\n// comment\nif (\n// comment\n a) {}\n }", options: ["never"] },
         { code: "{\n// comment\nif (\n// comment\n a) {}\n }", options: [{ blocks: "never" }] },
+
+        { code: "switch (a) {\ncase 0: foo();\n}", options: ["never"] },
         { code: "switch (a) {\ncase 0: foo();\n}", options: [{ switches: "never" }] },
-        { code: "class A{\nfoo(){}\n}", parserOptions: { ecmaVersion: 6 }, options: [{ classes: "never" }] }
+
+
+        { code: "class A{\nfoo(){}\n}", parserOptions: { ecmaVersion: 6 }, options: ["never"] },
+        { code: "class A{\nfoo(){}\n}", parserOptions: { ecmaVersion: 6 }, options: [{ classes: "never" }] },
+
+        // Ignore block statements if not configured
+        { code: "{\na();\n}", options: [{ switches: "always" }] },
+        { code: "{\n\na();\n\n}", options: [{ switches: "never" }] },
+
+        // Ignore switch statements if not configured
+        { code: "switch (a) {\ncase 0: foo();\ncase 1: bar();\n}", options: [{ blocks: "always", classes: "always" }] },
+        { code: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}", options: [{ blocks: "never", classes: "never" }] },
+
+
+        // Ignore class statements if not configured
+        { code: "class A{\nfoo(){}\n}", parserOptions: { ecmaVersion: 6 }, options: [{ blocks: "always" }] },
+        { code: "class A{\n\nfoo(){}\n\n}", parserOptions: { ecmaVersion: 6 }, options: [{ blocks: "never" }] }
+
     ],
     invalid: [
         {
@@ -214,6 +224,23 @@ ruleTester.run("padded-blocks", rule, {
                 }
             ]
         },
+        {
+            code: "switch (a) {\ncase 0: foo();\ncase 1: bar();\n}",
+            output: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}",
+            options: ["always"],
+            errors: [
+                {
+                    message: ALWAYS_MESSAGE,
+                    line: 1,
+                    column: 12
+                },
+                {
+                    message: ALWAYS_MESSAGE,
+                    line: 4,
+                    column: 1
+                }
+            ]
+        },
         {
             code: "switch (a) {\ncase 0: foo();\ncase 1: bar();\n}",
             output: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}",
@@ -248,6 +275,24 @@ ruleTester.run("padded-blocks", rule, {
                 }
             ]
         },
+        {
+            code: "class A {\nconstructor(){}\n}",
+            output: "class A {\n\nconstructor(){}\n\n}",
+            parserOptions: { ecmaVersion: 6 },
+            options: ["always"],
+            errors: [
+                {
+                    message: ALWAYS_MESSAGE,
+                    line: 1,
+                    column: 9
+                },
+                {
+                    message: ALWAYS_MESSAGE,
+                    line: 3,
+                    column: 1
+                }
+            ]
+        },
         {
             code: "class A {\nconstructor(){}\n}",
             output: "class A {\n\nconstructor(){}\n\n}",
@@ -416,6 +461,23 @@ ruleTester.run("padded-blocks", rule, {
                 }
             ]
         },
+        {
+            code: "switch (a) {\n\ncase 0: foo();\n\n}",
+            output: "switch (a) {\ncase 0: foo();\n}",
+            options: ["never"],
+            errors: [
+                {
+                    message: NEVER_MESSAGE,
+                    line: 1,
+                    column: 12
+                },
+                {
+                    message: NEVER_MESSAGE,
+                    line: 5,
+                    column: 1
+                }
+            ]
+        },
         {
             code: "switch (a) {\n\ncase 0: foo();\n}",
             output: "switch (a) {\ncase 0: foo();\n}",
@@ -440,6 +502,30 @@ ruleTester.run("padded-blocks", rule, {
                 }
             ]
         },
+        {
+            code: "class A {\n\nconstructor(){\n\nfoo();\n\n}\n\n}",
+            output: "class A {\nconstructor(){\nfoo();\n}\n}",
+            parserOptions: { ecmaVersion: 6 },
+            options: ["never"],
+            errors: [
+                {
+                    message: NEVER_MESSAGE,
+                    line: 1
+                },
+                {
+                    message: NEVER_MESSAGE,
+                    line: 3
+                },
+                {
+                    message: NEVER_MESSAGE,
+                    line: 7
+                },
+                {
+                    message: NEVER_MESSAGE,
+                    line: 9
+                }
+            ]
+        },
         {
             code: "class A {\n\nconstructor(){\n\nfoo();\n\n}\n\n}",
             output: "class A {\nconstructor(){\n\nfoo();\n\n}\n}",
diff --git a/tests/lib/rules/space-before-function-paren.js b/tests/lib/rules/space-before-function-paren.js
index 26180be5f..5e37dfd4e 100644
--- a/tests/lib/rules/space-before-function-paren.js
+++ b/tests/lib/rules/space-before-function-paren.js
@@ -8,8 +8,9 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const rule = require("../../../lib/rules/space-before-function-paren"),
-    RuleTester = require("../../../lib/testers/rule-tester");
+const rule = require("../../../lib/rules/space-before-function-paren");
+const RuleTester = require("../../../lib/testers/rule-tester");
+const baseParser = require("../../fixtures/fixture-parser");
 
 //------------------------------------------------------------------------------
 // Tests
@@ -95,6 +96,10 @@ ruleTester.run("space-before-function-paren", rule, {
         { code: "var bar = function foo () {}",
             options: [{ named: "ignore", anonymous: "always" }]
         },
+        {
+            code: "type TransformFunction = (el: ASTElement, code: string) => string;",
+            parser: baseParser("babel-eslint7", "function-type-annotation")
+        },
 
         // Async arrow functions
         { code: "() => 1", parserOptions: { ecmaVersion: 6 } },
diff --git a/tests/lib/util/glob-util.js b/tests/lib/util/glob-util.js
index 452ca06b2..47175848f 100644
--- a/tests/lib/util/glob-util.js
+++ b/tests/lib/util/glob-util.js
@@ -144,6 +144,16 @@ describe("globUtil", () => {
             assert.deepEqual(result, ["one-js-file/example.js"]);
         });
 
+        it("should ignore empty patterns", () => {
+            const patterns = [""];
+            const opts = {
+                cwd: getFixturePath()
+            };
+            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+
+            assert.deepEqual(result, []);
+        });
+
     });
 
     describe("listFilesToProcess()", () => {