Repository: eslint/eslint (js)

Issue:
padded-blocks: Change default behavior so that string config affects blocks, classes, and switch statements
**What rule do you want to change?**

padded-blocks

**Does this change cause the rule to produce more or fewer warnings?**

More in certain circumstances.

**How will the change be implemented? (New option, new default behavior, etc.)?**

Change default behavior so that a configuration of `"always"` or `"never"` will affect classes and switch statements, as well as blocks.

Currently `"always"` and `"never"` only affect blocks for backward compatibility reasons. This proposal is to change that behavior (making the rule more intuitive and consistent) in a major release.

**Please provide some example code that this change will affect:**

```js
/* eslint padded-blocks: ["error", "always"] */

switch (foo) {
    case 1:
        doSomething();
        break;
}

class Foo {
    bar() {
        doSomething();
    }
}
```

**What does the rule currently do for this code?**

Does not warn, since these are not BlockStatements.

**What will the rule do after it's changed?**

Warn-- the switch and class lack appropriate padding. Analogous cases can be created for the `"never"` string configuration as well.

Pull request:
Breaking: change defaults for padded-blocks (fixes #7879)
**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))
[X] 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
[ ] Other, please explain:

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (http://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**
Changed defaults for `padded-blocks` to lint classes and switches with `always` and `never`.

**Is there anything you'd like reviewers to focus on?**
No.



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/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/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/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-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-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-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/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/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..3cb48505e 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": {


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/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()", () => {