Repository: eslint/eslint (js)

Issue:
False-positive in prefer-const and array-destructuring
**Tell us about your environment**

* **ESLint Version:** 3.18.0
* **Node Version:** 6.10.0
* **npm Version:** 4.4.4

**What parser (default, Babel-ESLint, etc.) are you using?**
default

**Please show your full configuration:**

```json
{
  "ecmaVersion": 7,
  "rules": [
    "prefer-const"
  ]
}
```

**What did you do? Please include the actual source code causing the issue.**

```js
let predicate;
[typeNode.returnType, predicate] = foo();
```

**What did you expect to happen?**

No error

**What actually happened? Please include the actual, raw output from ESLint.**

```
2:23 - 'predicate' is never reassigned. Use 'const' instead. (prefer-const)
```

The rule should consider that it is not possible to actually make predicate a const here.


Pull request description:
Fix: prefer-const when using destructuring assign (fixes #8308)
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[ ] Documentation update
[x] 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
[ ] Other, please explain:

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**

Changed `prefer-const` so that it considers destructuring assignment with an object property to disqualify using `const` for variables used in the same destructuring assignment.


**Is there anything you'd like reviewers to focus on?**

Is this the correct approach? It seems like the key to fixing this bug was to consider object properties in destructuring assignment to be the key factor in determining if a variable should be declared with `const`. I'm not 100% this is the correct assumption, so please double-check that.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2848b4c91..7572d6d71 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,21 @@
+v5.7.0 - October 12, 2018
+
+* 6cb63fd Update: Add iife to padding-line-between-statements (fixes #10853) (#10916) (Kevin Partington)
+* 5fd1bda Update: no-tabs allowIndentationTabs option (fixes #10256) (#10925) (Kevin Partington)
+* d12be69 Fix: no-extra-bind No autofix if arg may have side effect (fixes #10846) (#10918) (Kevin Partington)
+* 847372f Fix: no-unused-vars false pos. with markVariableAsUsed (fixes #10952) (#10954) (Roy Sutton)
+* 4132de7 Chore: Simplify space-infix-ops (#10935) (Bence Dányi)
+* 543edfa Fix: Fix error with one-var (fixes #10937) (#10938) (Justin Krup)
+* 95c4cb1 Docs: Fix typo for no-unsafe-finally (#10945) (Sergio Santoro)
+* 5fe0e1a Fix: no-invalid-regexp disallows \ at end of pattern (fixes #10861) (#10920) (Toru Nagashima)
+* f85547a Docs: Add 'When Not To Use' section to space-infix-ops (#10931) (Bence Dányi)
+* 3dccac4 Docs: Update working-with-parsers link (#10929) (Azeem Bande-Ali)
+* 557a8bb Docs: Remove old note about caching, add a new one (fixes #10739) (#10913) (Zac)
+* fe8111a Chore: Add more test cases to space-infix-ops (#10936) (Bence Dányi)
+* 066f7e0 Update: camelcase rule ignoreList added (#10783) (Julien Martin)
+* 70bde69 Upgrade: table to version 5 (#10903) (Rouven Weßling)
+* 2e52bca Chore: Update issue templates (#10900) (Nicholas C. Zakas)
+
 v5.6.1 - September 28, 2018
 
 * 9b26bdb Fix: avoid exponential require-atomic-updates traversal (fixes #10893) (#10894) (Teddy Katz)
diff --git a/Makefile.js b/Makefile.js
index 3c514af09..ee7d37b24 100644
--- a/Makefile.js
+++ b/Makefile.js
@@ -23,23 +23,11 @@ const lodash = require("lodash"),
     os = require("os"),
     path = require("path"),
     semver = require("semver"),
-    shell = require("shelljs"),
     ejs = require("ejs"),
     loadPerf = require("load-perf"),
     yaml = require("js-yaml");
 
-const cat = shell.cat;
-const cd = shell.cd;
-const cp = shell.cp;
-const echo = shell.echo;
-const exec = shell.exec;
-const exit = shell.exit;
-const find = shell.find;
-const ls = shell.ls;
-const mkdir = shell.mkdir;
-const pwd = shell.pwd;
-const rm = shell.rm;
-const test = shell.test;
+const { cat, cd, cp, echo, exec, exit, find, ls, mkdir, pwd, rm, test } = require("shelljs");
 
 //------------------------------------------------------------------------------
 // Settings
diff --git a/docs/developer-guide/README.md b/docs/developer-guide/README.md
index 2070b2da1..ea1943099 100644
--- a/docs/developer-guide/README.md
+++ b/docs/developer-guide/README.md
@@ -34,7 +34,7 @@ You're finally ready to start working with rules. You may want to fix an existin
 
 You've developed library-specific rules for ESLint and you want to share it with the community. You can publish an ESLint plugin on npm.
 
-## Section 6: [Working with Parsers](working-with-parsers.md)
+## Section 6: [Working with Custom Parsers](working-with-custom-parsers.md)
 
 If you aren't going to use the default parser of ESLint, this section explains about using custom parsers.
 
diff --git a/docs/rules/no-tabs.md b/docs/rules/no-tabs.md
index 691b2f2af..4e02d9a04 100644
--- a/docs/rules/no-tabs.md
+++ b/docs/rules/no-tabs.md
@@ -9,14 +9,14 @@ This rule looks for tabs anywhere inside a file: code, comments or anything else
 Examples of **incorrect** code for this rule:
 
 ```js
-var a /t= 2;
+var a \t= 2;
 
 /**
-* /t/t it's a test function
+* \t\t it's a test function
 */
 function test(){}
 
-var x = 1; // /t test
+var x = 1; // \t test
 ```
 
 Examples of **correct** code for this rule:
@@ -32,9 +32,29 @@ function test(){}
 var x = 1; // test
 ```
 
+### Options
+
+This rule has an optional object option with the following properties:
+
+* `allowIndentationTabs` (default: false): If this is set to true, then the rule will not report tabs used for indentation.
+
+#### allowIndentationTabs
+
+Examples of **correct** code for this rule with the `allowIndentationTabs: true` option:
+
+```js
+/* eslint no-tabs: ["error", { allowIndentationTabs: true }] */
+
+function test() {
+\tdoSomething();
+}
+
+\t// comment with leading indentation tab
+```
+
 ## When Not To Use It
 
-If you have established a standard where having tabs is fine.
+If you have established a standard where having tabs is fine, then you can disable this rule.
 
 ## Compatibility
 
diff --git a/docs/rules/no-unsafe-finally.md b/docs/rules/no-unsafe-finally.md
index 1783e501f..fb3bb1ea5 100644
--- a/docs/rules/no-unsafe-finally.md
+++ b/docs/rules/no-unsafe-finally.md
@@ -49,7 +49,7 @@ JavaScript suspends the control flow statements of `try` and `catch` blocks unti
 // We expect this function to return 0 from try block.
 (() => {
   label: try {
-    return 0; // 1 is returned but suspended until finally block ends
+    return 0; // 0 is returned but suspended until finally block ends
   } finally {
     break label; // It breaks out the try-finally block, before 0 is returned.
   }
diff --git a/docs/rules/padding-line-between-statements.md b/docs/rules/padding-line-between-statements.md
index c56259734..390dada29 100644
--- a/docs/rules/padding-line-between-statements.md
+++ b/docs/rules/padding-line-between-statements.md
@@ -20,9 +20,9 @@ function foo() {
 
 ## Rule Details
 
-This rule does nothing if no configuration.
+This rule does nothing if no configurations are provided.
 
-A configuration is an object which has 3 properties; `blankLine`, `prev` and `next`. For example, `{ blankLine: "always", prev: "var", next: "return" }` means "it requires one or more blank lines between a variable declaration and a `return` statement."
+A configuration is an object which has 3 properties; `blankLine`, `prev` and `next`. For example, `{ blankLine: "always", prev: "var", next: "return" }` means "one or more blank lines are required between a variable declaration and a `return` statement."
 You can supply any number of configurations. If a statement pair matches multiple configurations, the last matched configuration will be used.
 
 ```json
@@ -46,11 +46,11 @@ You can supply any number of configurations. If a statement pair matches multipl
 - `STATEMENT_TYPE` is one of the following, or an array of the following.
     - `"*"` is wildcard. This matches any statements.
     - `"block"` is lonely blocks.
-    - `"block-like"` is block like statements. This matches statements that the last token is the closing brace of blocks; e.g. `{ }`, `if (a) { }`, and `while (a) { }`.
+    - `"block-like"` is block like statements. This matches statements that the last token is the closing brace of blocks; e.g. `{ }`, `if (a) { }`, and `while (a) { }`. Also matches immediately invoked function expression statements.
     - `"break"` is `break` statements.
     - `"case"` is `case` labels.
-    - `"cjs-export"` is `export` statements of CommonJS; e.g. `module.exports = 0`, `module.exports.foo = 1`, and `exports.foo = 2`. This is the special cases of assignment.
-    - `"cjs-import"` is `import` statements of CommonJS; e.g. `const foo = require("foo")`. This is the special cases of variable declarations.
+    - `"cjs-export"` is `export` statements of CommonJS; e.g. `module.exports = 0`, `module.exports.foo = 1`, and `exports.foo = 2`. This is a special case of assignment.
+    - `"cjs-import"` is `import` statements of CommonJS; e.g. `const foo = require("foo")`. This is a special case of variable declarations.
     - `"class"` is `class` declarations.
     - `"const"` is `const` variable declarations.
     - `"continue"` is `continue` statements.
@@ -64,6 +64,7 @@ You can supply any number of configurations. If a statement pair matches multipl
     - `"for"` is `for` loop families. This matches all statements that the first token is `for` keyword.
     - `"function"` is function declarations.
     - `"if"` is `if` statements.
+    - `"iife"` is immediately invoked function expression statements. This matches calls on a function expression, optionally prefixed with a unary operator.
     - `"import"` is `import` declarations.
     - `"let"` is `let` variable declarations.
     - `"multiline-block-like"` is block like statements. This is the same as `block-like` type, but only if the block is multiline.
diff --git a/docs/rules/prefer-const.md b/docs/rules/prefer-const.md
index cf86f5b7b..3e5a5d0c3 100644
--- a/docs/rules/prefer-const.md
+++ b/docs/rules/prefer-const.md
@@ -79,6 +79,15 @@ for (let i = 0, end = 10; i < end; ++i) {
     console.log(a);
 }
 
+// `predicate` is only assigned once but cannot be separately declared as `const`
+let predicate;
+[object.type, predicate] = foo();
+
+// `a` is only assigned once but cannot be separately declared as `const`
+let a;
+const b = {};
+({ a, c: b.c } = func());
+
 // suggest to use `no-var` rule.
 var b = 3;
 console.log(b);
diff --git a/docs/rules/space-infix-ops.md b/docs/rules/space-infix-ops.md
index f0381877d..406e2030c 100644
--- a/docs/rules/space-infix-ops.md
+++ b/docs/rules/space-infix-ops.md
@@ -73,3 +73,7 @@ var {a = 0} = bar;
 
 function foo(a = 0) { }
 ```
+
+## When Not To Use It
+
+You can turn this rule off if you are not concerned with the consistency of spacing around infix operators.
diff --git a/docs/user-guide/command-line-interface.md b/docs/user-guide/command-line-interface.md
index 7de5a50a1..62ecd3c20 100644
--- a/docs/user-guide/command-line-interface.md
+++ b/docs/user-guide/command-line-interface.md
@@ -401,7 +401,7 @@ Store the info about processed files in order to only operate on the changed one
 
 **Note:** If you run ESLint with `--cache` and then run ESLint without `--cache`, the `.eslintcache` file will be deleted. This is necessary because the results of the lint might change and make `.eslintcache` invalid. If you want to control when the cache file is deleted, then use `--cache-location` to specify an alternate location for the cache file.
 
-**Note:**: As of now, only the results for successfully linted files are stored in the cache. Files which fail linting are not stored in the cache, so they will be linted every time.
+**Note:**: Autofixed files are not placed in the cache. Subsequent linting that does not trigger an autofix will place it in the cache.
 
 #### `--cache-file`
 
diff --git a/karma.conf.js b/karma.conf.js
index 29a8cdc8f..0ffab8bc5 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -67,13 +67,8 @@ module.exports = function(config) {
 
         // start these browsers
         // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
-        browsers: ["HeadlessChrome"],
-        customLaunchers: {
-          HeadlessChrome: {
-            base: 'ChromeHeadless',
-            flags: [ '--no-sandbox', ],
-             },
-            },
+        browsers: ["PhantomJS"],
+
 
         // Continuous Integration mode
         // if true, Karma captures browsers, runs the tests and exits
diff --git a/lib/rules/no-extra-bind.js b/lib/rules/no-extra-bind.js
index b8376adfc..6d6cad13e 100644
--- a/lib/rules/no-extra-bind.js
+++ b/lib/rules/no-extra-bind.js
@@ -10,6 +10,12 @@
 
 const astUtils = require("../util/ast-utils");
 
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const SIDE_EFFECT_FREE_NODE_TYPES = new Set(["Literal", "Identifier", "ThisExpression", "FunctionExpression"]);
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -35,6 +41,18 @@ module.exports = {
     create(context) {
         let scopeInfo = null;
 
+        /**
+         * Checks if a node is free of side effects.
+         *
+         * This check is stricter than it needs to be, in order to keep the implementation simple.
+         *
+         * @param {ASTNode} node A node to check.
+         * @returns {boolean} True if the node is known to be side-effect free, false otherwise.
+         */
+        function isSideEffectFree(node) {
+            return SIDE_EFFECT_FREE_NODE_TYPES.has(node.type);
+        }
+
         /**
          * Reports a given function node.
          *
@@ -48,6 +66,10 @@ module.exports = {
                 messageId: "unexpected",
                 loc: node.parent.property.loc.start,
                 fix(fixer) {
+                    if (node.parent.parent.arguments.length && !isSideEffectFree(node.parent.parent.arguments[0])) {
+                        return null;
+                    }
+
                     const firstTokenToRemove = context.getSourceCode()
                         .getFirstTokenBetween(node.parent.object, node.parent.property, astUtils.isNotClosingParenToken);
 
diff --git a/lib/rules/no-tabs.js b/lib/rules/no-tabs.js
index 08a8fa5b7..c22a94da3 100644
--- a/lib/rules/no-tabs.js
+++ b/lib/rules/no-tabs.js
@@ -8,7 +8,9 @@
 //------------------------------------------------------------------------------
 // Helpers
 //------------------------------------------------------------------------------
-const regex = /\t/;
+
+const tabRegex = /\t+/g;
+const anyNonWhitespaceRegex = /\S/;
 
 //------------------------------------------------------------------------------
 // Public Interface
@@ -22,21 +24,36 @@ module.exports = {
             recommended: false,
             url: "https://eslint.org/docs/rules/no-tabs"
         },
-        schema: []
+        schema: [{
+            type: "object",
+            properties: {
+                allowIndentationTabs: {
+                    type: "boolean"
+                }
+            },
+            additionalProperties: false
+        }]
     },
 
     create(context) {
+        const sourceCode = context.getSourceCode();
+        const allowIndentationTabs = context.options && context.options[0] && context.options[0].allowIndentationTabs;
+
         return {
             Program(node) {
-                context.getSourceCode().getLines().forEach((line, index) => {
-                    const match = regex.exec(line);
+                sourceCode.getLines().forEach((line, index) => {
+                    let match;
+
+                    while ((match = tabRegex.exec(line)) !== null) {
+                        if (allowIndentationTabs && !anyNonWhitespaceRegex.test(line.slice(0, match.index))) {
+                            continue;
+                        }
 
-                    if (match) {
                         context.report({
                             node,
                             loc: {
                                 line: index + 1,
-                                column: match.index + 1
+                                column: match.index
                             },
                             message: "Unexpected tab character."
                         });
diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
index fff3e33d9..6f36813ac 100644
--- a/lib/rules/no-unused-vars.js
+++ b/lib/rules/no-unused-vars.js
@@ -469,7 +469,7 @@ module.exports = {
             const posteriorParams = params.slice(params.indexOf(variable) + 1);
 
             // If any used parameters occur after this parameter, do not report.
-            return !posteriorParams.some(v => v.references.length > 0);
+            return !posteriorParams.some(v => v.references.length > 0 || v.eslintUsed);
         }
 
         /**
diff --git a/lib/rules/one-var.js b/lib/rules/one-var.js
index 15b664d77..3efd0f27f 100644
--- a/lib/rules/one-var.js
+++ b/lib/rules/one-var.js
@@ -314,6 +314,11 @@ module.exports = {
         function splitDeclarations(declaration) {
             return fixer => declaration.declarations.map(declarator => {
                 const tokenAfterDeclarator = sourceCode.getTokenAfter(declarator);
+
+                if (tokenAfterDeclarator === null) {
+                    return null;
+                }
+
                 const afterComma = sourceCode.getTokenAfter(tokenAfterDeclarator, { includeComments: true });
 
                 if (tokenAfterDeclarator.value !== ",") {
diff --git a/lib/rules/padding-line-between-statements.js b/lib/rules/padding-line-between-statements.js
index f571e1e2e..4af85fef0 100644
--- a/lib/rules/padding-line-between-statements.js
+++ b/lib/rules/padding-line-between-statements.js
@@ -353,6 +353,9 @@ const StatementTypes = {
             node.type === "ExpressionStatement" &&
             !isDirectivePrologue(node, sourceCode)
     },
+    iife: {
+        test: isIIFEStatement
+    },
     "multiline-block-like": {
         test: (node, sourceCode) =>
             node.loc.start.line !== node.loc.end.line &&
diff --git a/lib/rules/prefer-const.js b/lib/rules/prefer-const.js
index 774fcf064..8b3bc5e0e 100644
--- a/lib/rules/prefer-const.js
+++ b/lib/rules/prefer-const.js
@@ -57,6 +57,7 @@ function canBecomeVariableDeclaration(identifier) {
  * @returns {boolean} Indicates if the variable is from outer scope or function parameters.
  */
 function isOuterVariableInDestructing(name, initScope) {
+
     if (initScope.through.find(ref => ref.resolved && ref.resolved.name === name)) {
         return true;
     }
@@ -96,6 +97,54 @@ function getDestructuringHost(reference) {
     return node;
 }
 
+/**
+ * Determines if a destructuring assignment node contains
+ * any MemberExpression nodes. This is used to determine if a
+ * variable that is only written once using destructuring can be
+ * safely converted into a const declaration.
+ * @param {ASTNode} node The ObjectPattern or ArrayPattern node to check.
+ * @returns {boolean} True if the destructuring pattern contains
+ *      a MemberExpression, false if not.
+ */
+function hasMemberExpressionAssignment(node) {
+    switch (node.type) {
+        case "ObjectPattern":
+            return node.properties.some(prop => {
+                if (prop) {
+
+                    /*
+                     * Spread elements have an argument property while
+                     * others have a value property. Because different
+                     * parsers use different node types for spread elements,
+                     * we just check if there is an argument property.
+                     */
+                    return hasMemberExpressionAssignment(prop.argument || prop.value);
+                }
+
+                return false;
+            });
+
+        case "ArrayPattern":
+            return node.elements.some(element => {
+                if (element) {
+                    return hasMemberExpressionAssignment(element);
+                }
+
+                return false;
+            });
+
+        case "AssignmentPattern":
+            return hasMemberExpressionAssignment(node.left);
+
+        case "MemberExpression":
+            return true;
+
+        // no default
+    }
+
+    return false;
+}
+
 /**
  * Gets an identifier node of a given variable.
  *
@@ -148,7 +197,8 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
 
             if (destructuringHost !== null && destructuringHost.left !== void 0) {
                 const leftNode = destructuringHost.left;
-                let hasOuterVariables = false;
+                let hasOuterVariables = false,
+                    hasNonIdentifiers = false;
 
                 if (leftNode.type === "ObjectPattern") {
                     const properties = leftNode.properties;
@@ -157,16 +207,23 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
                         .filter(prop => prop.value)
                         .map(prop => prop.value.name)
                         .some(name => isOuterVariableInDestructing(name, variable.scope));
+
+                    hasNonIdentifiers = hasMemberExpressionAssignment(leftNode);
+
                 } else if (leftNode.type === "ArrayPattern") {
                     const elements = leftNode.elements;
 
                     hasOuterVariables = elements
                         .map(element => element && element.name)
                         .some(name => isOuterVariableInDestructing(name, variable.scope));
+
+                    hasNonIdentifiers = hasMemberExpressionAssignment(leftNode);
                 }
-                if (hasOuterVariables) {
+
+                if (hasOuterVariables || hasNonIdentifiers) {
                     return null;
                 }
+
             }
 
             writer = reference;
@@ -192,9 +249,11 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
     if (!shouldBeConst) {
         return null;
     }
+
     if (isReadBeforeInit) {
         return variable.defs[0].name;
     }
+
     return writer.identifier;
 }
 
@@ -295,7 +354,7 @@ module.exports = {
     create(context) {
         const options = context.options[0] || {};
         const sourceCode = context.getSourceCode();
-        const checkingMixedDestructuring = options.destructuring !== "all";
+        const shouldMatchAnyDestructuredVariable = options.destructuring !== "all";
         const ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true;
         const variables = [];
 
@@ -316,7 +375,7 @@ module.exports = {
         function checkGroup(nodes) {
             const nodesToReport = nodes.filter(Boolean);
 
-            if (nodes.length && (checkingMixedDestructuring || nodesToReport.length === nodes.length)) {
+            if (nodes.length && (shouldMatchAnyDestructuredVariable || nodesToReport.length === nodes.length)) {
                 const varDeclParent = findUp(nodes[0], "VariableDeclaration", parentNode => parentNode.type.endsWith("Statement"));
                 const shouldFix = varDeclParent &&
 
diff --git a/lib/rules/space-infix-ops.js b/lib/rules/space-infix-ops.js
index 49b64658d..17b49cc11 100644
--- a/lib/rules/space-infix-ops.js
+++ b/lib/rules/space-infix-ops.js
@@ -34,37 +34,25 @@ module.exports = {
 
     create(context) {
         const int32Hint = context.options[0] ? context.options[0].int32Hint === true : false;
-
-        const OPERATORS = [
-            "*", "/", "%", "+", "-", "<<", ">>", ">>>", "<", "<=", ">", ">=", "in",
-            "instanceof", "==", "!=", "===", "!==", "&", "^", "|", "&&", "||", "=",
-            "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "^=", "|=",
-            "?", ":", ",", "**"
-        ];
-
         const sourceCode = context.getSourceCode();
 
         /**
          * Returns the first token which violates the rule
          * @param {ASTNode} left - The left node of the main node
          * @param {ASTNode} right - The right node of the main node
+         * @param {string} op - The operator of the main node
          * @returns {Object} The violator token or null
          * @private
          */
-        function getFirstNonSpacedToken(left, right) {
-            const tokens = sourceCode.getTokensBetween(left, right, 1);
-
-            for (let i = 1, l = tokens.length - 1; i < l; ++i) {
-                const op = tokens[i];
-
-                if (
-                    (op.type === "Punctuator" || op.type === "Keyword") &&
-                    OPERATORS.indexOf(op.value) >= 0 &&
-                    (tokens[i - 1].range[1] >= op.range[0] || op.range[1] >= tokens[i + 1].range[0])
-                ) {
-                    return op;
-                }
+        function getFirstNonSpacedToken(left, right, op) {
+            const operator = sourceCode.getFirstTokenBetween(left, right, token => token.value === op);
+            const prev = sourceCode.getTokenBefore(operator);
+            const next = sourceCode.getTokenAfter(operator);
+
+            if (!sourceCode.isSpaceBetweenTokens(prev, operator) || !sourceCode.isSpaceBetweenTokens(operator, next)) {
+                return operator;
             }
+
             return null;
         }
 
@@ -110,7 +98,10 @@ module.exports = {
             const leftNode = (node.left.typeAnnotation) ? node.left.typeAnnotation : node.left;
             const rightNode = node.right;
 
-            const nonSpacedNode = getFirstNonSpacedToken(leftNode, rightNode);
+            // search for = in AssignmentPattern nodes
+            const operator = node.operator || "=";
+
+            const nonSpacedNode = getFirstNonSpacedToken(leftNode, rightNode, operator);
 
             if (nonSpacedNode) {
                 if (!(int32Hint && sourceCode.getText(node).endsWith("|0"))) {
@@ -126,8 +117,8 @@ module.exports = {
          * @private
          */
         function checkConditional(node) {
-            const nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent);
-            const nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate);
+            const nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent, "?");
+            const nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate, ":");
 
             if (nonSpacedConsequesntNode) {
                 report(node, nonSpacedConsequesntNode);
@@ -147,7 +138,7 @@ module.exports = {
             const rightNode = node.init;
 
             if (rightNode) {
-                const nonSpacedNode = getFirstNonSpacedToken(leftNode, rightNode);
+                const nonSpacedNode = getFirstNonSpacedToken(leftNode, rightNode, "=");
 
                 if (nonSpacedNode) {
                     report(node, nonSpacedNode);
diff --git a/package.json b/package.json
index e970cf87c..dd3fe4615 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint",
-  "version": "5.6.1",
+  "version": "5.7.0",
   "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
   "description": "An AST-based pattern checker for JavaScript.",
   "bin": {
@@ -66,7 +66,7 @@
     "path-is-inside": "^1.0.2",
     "pluralize": "^7.0.0",
     "progress": "^2.0.0",
-    "regexpp": "^2.0.0",
+    "regexpp": "^2.0.1",
     "require-uncached": "^1.0.3",
     "semver": "^5.5.1",
     "strip-ansi": "^4.0.0",
@@ -100,13 +100,14 @@
     "karma-babel-preprocessor": "^7.0.0",
     "karma-mocha": "^1.3.0",
     "karma-mocha-reporter": "^2.2.3",
-    "karma-chrome-launcher": "^2.2.0",
+    "karma-phantomjs-launcher": "^1.0.4",
     "leche": "^2.2.3",
     "load-perf": "^0.2.0",
     "markdownlint": "^0.11.0",
     "mocha": "^5.0.5",
     "mock-fs": "^4.6.0",
     "npm-license": "^0.3.3",
+    "phantomjs-prebuilt": "^2.1.16",
     "proxyquire": "^2.0.1",
     "shelljs": "^0.8.2",
     "sinon": "^3.3.0",


Test patch:
diff --git a/tests/fixtures/parsers/typescript-parsers/type-alias.js b/tests/fixtures/parsers/typescript-parsers/type-alias.js
new file mode 100644
index 000000000..f1d68c486
--- /dev/null
+++ b/tests/fixtures/parsers/typescript-parsers/type-alias.js
@@ -0,0 +1,155 @@
+"use strict";
+
+exports.parse = () => ({
+    type: "Program",
+    range: [0, 16],
+    loc: {
+        start: { line: 1, column: 0 },
+        end: { line: 1, column: 16 }
+    },
+    body: [
+        {
+            type: "VariableDeclaration",
+            range: [0, 16],
+            loc: {
+                start: { line: 1, column: 0 },
+                end: { line: 1, column: 16 }
+            },
+            kind: "type",
+            declarations: [
+                {
+                    type: "VariableDeclarator",
+                    id: {
+                        type: "Identifier",
+                        range: [
+                            5,
+                            8
+                        ],
+                        loc: {
+                            start: { line: 1, column: 5 },
+                            end: { line: 1, column: 8 }
+                        },
+                        name: "Foo"
+                    },
+                    init: {
+                        type: "TSTypeReference",
+                        range: [14, 15],
+                        loc: {
+                            start: { line: 1, column: 14 },
+                            end: { line: 1, column: 15 }
+                        },
+                        typeName: {
+                            type: "Identifier",
+                            range: [14, 15],
+                            loc: {
+                                start: { line: 1, column: 14 },
+                                end: { line: 1, column: 15 }
+                            },
+                            name: "T"
+                        }
+                    },
+                    range: [5, 16],
+                    loc: {
+                        start: { line: 1, column: 5 },
+                        end: { line: 1, column: 16 }
+                    },
+                    typeParameters: {
+                        type: "TSTypeParameterDeclaration",
+                        range: [8, 11],
+                        loc: {
+                            start: { line: 1, column: 8 },
+                            end: { line: 1, column: 11 }
+                        },
+                        params: [
+                            {
+                                type: "TSTypeParameter",
+                                range: [9, 10],
+                                loc: {
+                                    start: { line: 1, column: 9 },
+                                    end: { line: 1, column: 10 }
+                                },
+                                name: "T"
+                            }
+                        ]
+                    }
+                }
+            ]
+        }
+    ],
+    sourceType: "script",
+    tokens: [
+        {
+            type: "Identifier",
+            value: "type",
+            range: [0, 4],
+            loc: {
+                start: { line: 1, column: 0 },
+                end: { line: 1, column: 4 }
+            }
+        },
+        {
+            type: "Identifier",
+            value: "Foo",
+            range: [5, 8],
+            loc: {
+                start: { line: 1, column: 5 },
+                end: { line: 1, column: 8 }
+            }
+        },
+        {
+            type: "Punctuator",
+            value: "<",
+            range: [8, 9],
+            loc: {
+                start: { line: 1, column: 8 },
+                end: { line: 1, column: 9 }
+            }
+        },
+        {
+            type: "Identifier",
+            value: "T",
+            range: [9, 10],
+            loc: {
+                start: { line: 1, column: 9 },
+                end: { line: 1, column: 10 }
+            }
+        },
+        {
+            type: "Punctuator",
+            value: ">",
+            range: [10, 11],
+            loc: {
+                start: { line: 1, column: 10 },
+                end: { line: 1, column: 11 }
+            }
+        },
+        {
+            type: "Punctuator",
+            value: "=",
+            range: [12, 13],
+            loc: {
+                start: { line: 1, column: 12 },
+                end: { line: 1, column: 13 }
+            }
+        },
+        {
+            type: "Identifier",
+            value: "T",
+            range: [14, 15],
+            loc: {
+                start: { line: 1, column: 14 },
+                end: { line: 1, column: 15 }
+            }
+        },
+        {
+            type: "Punctuator",
+            value: ";",
+            range: [15, 16],
+            loc: {
+                start: { line: 1, column: 15 },
+                end: { line: 1, column: 16 }
+            }
+        }
+    ],
+    comments: []
+})
diff --git a/tests/lib/rules/no-extra-bind.js b/tests/lib/rules/no-extra-bind.js
index 4dfec87ac..4e5a08f36 100644
--- a/tests/lib/rules/no-extra-bind.js
+++ b/tests/lib/rules/no-extra-bind.js
@@ -70,10 +70,32 @@ ruleTester.run("no-extra-bind", rule, {
             output: "var a = function() { function c(){ this.d } }",
             errors
         },
+        {
+            code: "var a = function() { return 1; }.bind(this)",
+            output: "var a = function() { return 1; }",
+            errors
+        },
         {
             code: "var a = function() { (function(){ (function(){ this.d }.bind(c)) }) }.bind(b)",
             output: "var a = function() { (function(){ (function(){ this.d }.bind(c)) }) }",
             errors: [{ messageId: "unexpected", type: "CallExpression", column: 71 }]
+        },
+
+        // Should not autofix if bind expression args have side effects
+        {
+            code: "var a = function() {}.bind(b++)",
+            output: null,
+            errors
+        },
+        {
+            code: "var a = function() {}.bind(b())",
+            output: null,
+            errors
+        },
+        {
+            code: "var a = function() {}.bind(b.c)",
+            output: null,
+            errors
         }
     ]
 });
diff --git a/tests/lib/rules/no-invalid-regexp.js b/tests/lib/rules/no-invalid-regexp.js
index 305f4e0d3..0062a5bbc 100644
--- a/tests/lib/rules/no-invalid-regexp.js
+++ b/tests/lib/rules/no-invalid-regexp.js
@@ -46,6 +46,12 @@ ruleTester.run("no-invalid-regexp", rule, {
     invalid: [
         { code: "RegExp('[');", errors: [{ message: "Invalid regular expression: /[/: Unterminated character class.", type: "CallExpression" }] },
         { code: "RegExp('.', 'z');", errors: [{ message: "Invalid flags supplied to RegExp constructor 'z'.", type: "CallExpression" }] },
-        { code: "new RegExp(')');", errors: [{ message: "Invalid regular expression: /)/: Unmatched ')'.", type: "NewExpression" }] }
+        { code: "new RegExp(')');", errors: [{ message: "Invalid regular expression: /)/: Unmatched ')'.", type: "NewExpression" }] },
+
+        // https://github.com/eslint/eslint/issues/10861
+        {
+            code: String.raw`new RegExp('\\');`,
+            errors: [{ message: "Invalid regular expression: /\\/: \\ at end of pattern.", type: "NewExpression" }]
+        }
     ]
 });
diff --git a/tests/lib/rules/no-tabs.js b/tests/lib/rules/no-tabs.js
index a01d9dc16..b4989037d 100644
--- a/tests/lib/rules/no-tabs.js
+++ b/tests/lib/rules/no-tabs.js
@@ -23,7 +23,16 @@ ruleTester.run("no-tabs", rule, {
         "function test(){\n}",
         "function test(){\n" +
         "  //   sdfdsf \n" +
-        "}"
+        "}",
+
+        {
+            code: "\tdoSomething();",
+            options: [{ allowIndentationTabs: true }]
+        },
+        {
+            code: "\t// comment",
+            options: [{ allowIndentationTabs: true }]
+        }
     ],
     invalid: [
         {
@@ -31,7 +40,7 @@ ruleTester.run("no-tabs", rule, {
             errors: [{
                 message: ERROR_MESSAGE,
                 line: 1,
-                column: 18
+                column: 17
             }]
         },
         {
@@ -39,7 +48,7 @@ ruleTester.run("no-tabs", rule, {
             errors: [{
                 message: ERROR_MESSAGE,
                 line: 1,
-                column: 6
+                column: 5
             }]
         },
         {
@@ -50,7 +59,7 @@ ruleTester.run("no-tabs", rule, {
             errors: [{
                 message: ERROR_MESSAGE,
                 line: 2,
-                column: 6
+                column: 5
             }]
         },
         {
@@ -61,7 +70,7 @@ ruleTester.run("no-tabs", rule, {
             errors: [{
                 message: ERROR_MESSAGE,
                 line: 1,
-                column: 10
+                column: 9
             }]
         },
         {
@@ -73,14 +82,23 @@ ruleTester.run("no-tabs", rule, {
                 {
                     message: ERROR_MESSAGE,
                     line: 2,
-                    column: 6
+                    column: 5
                 },
                 {
                     message: ERROR_MESSAGE,
                     line: 3,
-                    column: 2
+                    column: 1
                 }
             ]
+        },
+        {
+            code: "\t// Comment with leading tab \t and inline tab",
+            options: [{ allowIndentationTabs: true }],
+            errors: [{
+                message: ERROR_MESSAGE,
+                line: 1,
+                column: 30
+            }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js
index f188f8ce3..316df18e0 100644
--- a/tests/lib/rules/no-unused-vars.js
+++ b/tests/lib/rules/no-unused-vars.js
@@ -271,7 +271,11 @@ ruleTester.run("no-unused-vars", rule, {
             code: "(({a, ...rest}) => rest)",
             options: [{ args: "all", ignoreRestSiblings: true }],
             parserOptions: { ecmaVersion: 2018 }
-        }
+        },
+
+        // https://github.com/eslint/eslint/issues/10952
+        "/*eslint use-every-a:1*/ !function(b, a) { return 1 }"
+
     ],
     invalid: [
         { code: "function foox() { return foox(); }", errors: [definedError("foox")] },
diff --git a/tests/lib/rules/one-var.js b/tests/lib/rules/one-var.js
index b628f512a..e5470d2e9 100644
--- a/tests/lib/rules/one-var.js
+++ b/tests/lib/rules/one-var.js
@@ -949,6 +949,17 @@ ruleTester.run("one-var", rule, {
                 column: 1
             }]
         },
+        {
+            code: "var a = 1, b = 2",
+            output: "var a = 1; var b = 2",
+            options: ["never"],
+            errors: [{
+                message: "Split 'var' declarations into multiple statements.",
+                type: "VariableDeclaration",
+                line: 1,
+                column: 1
+            }]
+        },
         {
             code: "var foo = require('foo'), bar;",
             output: null,
diff --git a/tests/lib/rules/padding-line-between-statements.js b/tests/lib/rules/padding-line-between-statements.js
index 3f72f8ff2..82147d389 100644
--- a/tests/lib/rules/padding-line-between-statements.js
+++ b/tests/lib/rules/padding-line-between-statements.js
@@ -852,6 +852,35 @@ ruleTester.run("padding-line-between-statements", rule, {
             ]
         },
 
+        //----------------------------------------------------------------------
+        // iife
+        //----------------------------------------------------------------------
+
+        {
+            code: "(function(){\n})()\n\nvar a = 2;",
+            options: [
+                { blankLine: "always", prev: "iife", next: "*" }
+            ]
+        },
+        {
+            code: "+(function(){\n})()\n\nvar a = 2;",
+            options: [
+                { blankLine: "always", prev: "iife", next: "*" }
+            ]
+        },
+        {
+            code: "(function(){\n})()\nvar a = 2;",
+            options: [
+                { blankLine: "never", prev: "iife", next: "*" }
+            ]
+        },
+        {
+            code: "+(function(){\n})()\nvar a = 2;",
+            options: [
+                { blankLine: "never", prev: "iife", next: "*" }
+            ]
+        },
+
         //----------------------------------------------------------------------
         // import
         //----------------------------------------------------------------------
@@ -3371,6 +3400,43 @@ ruleTester.run("padding-line-between-statements", rule, {
             errors: [MESSAGE_ALWAYS]
         },
 
+        //----------------------------------------------------------------------
+        // iife
+        //----------------------------------------------------------------------
+
+        {
+            code: "(function(){\n})()\n\nvar a = 2;",
+            output: "(function(){\n})()\nvar a = 2;",
+            options: [
+                { blankLine: "never", prev: "iife", next: "*" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "+(function(){\n})()\n\nvar a = 2;",
+            output: "+(function(){\n})()\nvar a = 2;",
+            options: [
+                { blankLine: "never", prev: "iife", next: "*" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "(function(){\n})()\nvar a = 2;",
+            output: "(function(){\n})()\n\nvar a = 2;",
+            options: [
+                { blankLine: "always", prev: "iife", next: "*" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+        {
+            code: "+(function(){\n})()\nvar a = 2;",
+            output: "+(function(){\n})()\n\nvar a = 2;",
+            options: [
+                { blankLine: "always", prev: "iife", next: "*" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+
         //----------------------------------------------------------------------
         // import
         //----------------------------------------------------------------------
@@ -4247,6 +4313,14 @@ ruleTester.run("padding-line-between-statements", rule, {
             ],
             errors: [MESSAGE_NEVER]
         },
+        {
+            code: "+(function(){\n})()\n\nvar a = 2;",
+            output: "+(function(){\n})()\nvar a = 2;",
+            options: [
+                { blankLine: "never", prev: "block-like", next: "*" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
         {
             code: "var a = function() {};\n\nvar b = 2;",
             output: "var a = function() {};\nvar b = 2;",
diff --git a/tests/lib/rules/prefer-const.js b/tests/lib/rules/prefer-const.js
index c7b8a93c2..f97320234 100644
--- a/tests/lib/rules/prefer-const.js
+++ b/tests/lib/rules/prefer-const.js
@@ -117,6 +117,54 @@ ruleTester.run("prefer-const", rule, {
             parser: fixtureParser("babel-eslint5/destructuring-object-spread")
         },
 
+        // https://github.com/eslint/eslint/issues/8308
+        {
+            code: "let predicate; [typeNode.returnType, predicate] = foo();",
+            parserOptions: { ecmaVersion: 2018 }
+        },
+        {
+            code: "let predicate; [typeNode.returnType, ...predicate] = foo();",
+            parserOptions: { ecmaVersion: 2018 }
+        },
+        {
+
+            // intentionally testing empty slot in destructuring assignment
+            code: "let predicate; [typeNode.returnType,, predicate] = foo();",
+            parserOptions: { ecmaVersion: 2018 }
+        },
+        {
+            code: "let predicate; [typeNode.returnType=5, predicate] = foo();",
+            parserOptions: { ecmaVersion: 2018 }
+        },
+        {
+            code: "let predicate; [[typeNode.returnType=5], predicate] = foo();",
+            parserOptions: { ecmaVersion: 2018 }
+        },
+        {
+            code: "let predicate; [[typeNode.returnType, predicate]] = foo();",
+            parserOptions: { ecmaVersion: 2018 }
+        },
+        {
+            code: "let predicate; [typeNode.returnType, [predicate]] = foo();",
+            parserOptions: { ecmaVersion: 2018 }
+        },
+        {
+            code: "let predicate; [, [typeNode.returnType, predicate]] = foo();",
+            parserOptions: { ecmaVersion: 2018 }
+        },
+        {
+            code: "let predicate; [, {foo:typeNode.returnType, predicate}] = foo();",
+            parserOptions: { ecmaVersion: 2018 }
+        },
+        {
+            code: "let predicate; [, {foo:typeNode.returnType, ...predicate}] = foo();",
+            parserOptions: { ecmaVersion: 2018 }
+        },
+        {
+            code: "let a; const b = {}; ({ a, c: b.c } = func());",
+            parserOptions: { ecmaVersion: 2018 }
+        },
+
         // ignoreReadBeforeAssign
         {
             code: "let x; function foo() { bar(x); } x = 0;",
@@ -380,6 +428,33 @@ ruleTester.run("prefer-const", rule, {
                 { message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" },
                 { message: "'z' is never reassigned. Use 'const' instead.", type: "Identifier" }
             ]
+        },
+
+        // https://github.com/eslint/eslint/issues/8308
+        {
+            code: "let predicate; [, {foo:returnType, predicate}] = foo();",
+            output: null,
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                { message: "'predicate' is never reassigned. Use 'const' instead.", type: "Identifier" }
+            ]
+        },
+        {
+            code: "let predicate; [, {foo:returnType, predicate}, ...bar ] = foo();",
+            output: null,
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                { message: "'predicate' is never reassigned. Use 'const' instead.", type: "Identifier" }
+            ]
+        },
+        {
+            code: "let predicate; [, {foo:returnType, ...predicate} ] = foo();",
+            output: null,
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                { message: "'predicate' is never reassigned. Use 'const' instead.", type: "Identifier" }
+            ]
         }
+
     ]
 });
diff --git a/tests/lib/rules/space-infix-ops.js b/tests/lib/rules/space-infix-ops.js
index 3f98c88d4..34eada46e 100644
--- a/tests/lib/rules/space-infix-ops.js
+++ b/tests/lib/rules/space-infix-ops.js
@@ -18,8 +18,14 @@ const ruleTester = new RuleTester();
 ruleTester.run("space-infix-ops", rule, {
     valid: [
         "a + b",
+        "a + ++b",
+        "a++ + b",
+        "a++ + ++b",
         "a     + b",
         "(a) + (b)",
+        "((a)) + ((b))",
+        "(((a))) + (((b)))",
+        "a + +b",
         "a + (b)",
         "a + +(b)",
         "a + (+(b))",
@@ -38,7 +44,10 @@ ruleTester.run("space-infix-ops", rule, {
         { code: "function foo(a: number = 0) { }", parserOptions: { ecmaVersion: 6 }, parser: parser("type-annotations/function-parameter-type-annotation") },
         { code: "function foo(): Bar { }", parserOptions: { ecmaVersion: 6 }, parser: parser("type-annotations/function-return-type-annotation") },
         { code: "var foo: Bar = '';", parserOptions: { ecmaVersion: 6 }, parser: parser("type-annotations/variable-declaration-init-type-annotation") },
-        { code: "const foo = function(a: number = 0): Bar { };", parserOptions: { ecmaVersion: 6 }, parser: parser("type-annotations/function-expression-type-annotation") }
+        { code: "const foo = function(a: number = 0): Bar { };", parserOptions: { ecmaVersion: 6 }, parser: parser("type-annotations/function-expression-type-annotation") },
+
+        // TypeScript Type Aliases
+        { code: "type Foo<T> = T;", parserOptions: { ecmaVersion: 6 }, parser: parser("typescript-parsers/type-alias") }
     ],
     invalid: [
         {